I have a method in a class that is supposed to only throw error log messages and then another method in another function that will get this errors and console them (for now).
The problem is that it just throws the error in the console and not in an upper level...
This are the methods from file1.ts:
private sendToApp2(App2Url: string, logObject: object) {
try
{
let uriOptions = {
host: this.hostname,
port: this.port,
path: '/App2',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Api-version': '1'
}
};
this.App2Call(uriOptions, JSON.stringify(logObject));
}
catch (err) {
throw err;
}
}
private App2Call(params: Object, data: string) {
return new Promise((resolve, reject) => {
try {
let req = http.request(params, (response) => {
response.on('data', (data) => {
resolve(data);
});
}).on('error', (err: Error) => {
reject(new Error(err.message));
});
req.write(data);
req.end();
}
catch (err) {
reject(new Error(err.message));
}
});
}
And in the second file, I do this logic to catch the error and console it:
GetErrors() {
try {
// initialize the class object
let getErrors = new FirstClass();
await getErrors.sendToApp2(this.App2Url, this.logObject);
}
catch (err) {
console.log(err);
}
}
It looks like a simple case of having forgotten to use async on the definition of sendToApp2. Since it's not async, there are no errors thrown during sendToApp2 since it returns before the promise from App2Call rejects.
Where you're using sendToApp2 you're using await, which suggests you're expecting it to return a promise, so just add async to the definition:
private async sendToApp2(App2Url: string, logObject: object) {
// ^^^^^
Then the try/catch can handle rejections as errors.
Side note: Right now, there's no point to the try/catch in sendToApp2, since all it does is throw err.
return a promise from the sendToApp2 and deal with the errors when you call the function
private sendToApp2(App2Url: string, logObject: object) {
let uriOptions = {
host: this.hostname,
port: this.port,
path: '/App2',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Api-version': '1'
}
};
return this.App2Call(uriOptions, JSON.stringify(logObject));
}
etErrors.sendToApp2(this.App2Url, this.logObject).then(
function(){},
function(err){ //error callback,or you can use catch();
alert(err);
});
Related
I have a method that uses node-fetch to make a POST call to update a profile object in a table via an API. If an invalid profileId is provided (status 404) the promise still resolves. What's the best way to handle it so that I can only accept status 200? The method is defined as:
async function updateUserProfileSocketId(profileId, socketId) {
const body = { id: profileId, socketId };
try {
const response = await fetch(`${API_URL}/updateUserProfile`, {
method: 'post',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (response.status !== 200) {
throw new Error(response.status);
}
} catch (err) {
console.log(`updateUserProfileSocketId Error: ${err}`);
}
}
And the method is called in a service class like this:
onInit(socket) {
socket.on('init', (profile) => {
Promise.resolve(updateUserProfileSocketId(profile.id, socket.id))
.then((response) => {
if (response === null || response === undefined) {
console.log(`Unable to find profile ${profile.id}`);
socket.conn.close();
} else {
users.push(profile.id);
}
})
.catch((err) => {
console.log(err);
});
});
}
This seems to work, but I'm not sure if this is the best way to handle this. Any ideas?
If the response status is not 200, you throw an exception that will immediately be caught again. This is probably not what you want. You can leave the catch block for logging purposes, but you should rethrow the exception:
async function updateUserProfileSocketId(profileId, socketId) {
const body = { id: profileId, socketId };
try {
const response = await fetch(...);
if (response.status !== 200) {
throw new Error(response.status);
}
} catch (err) {
console.log(`updateUserProfileSocketId Error: ${err}`);
throw err;
}
}
The same thing applies to the catch-handler inside the socket-callback.
However, removing the try/catch/log/rethrow logic and handling the exception centrally would be cleaner.
Hi I have following function returning promise
module.exports.getJwtToken = async() => {
const httpSearchAddressUXConfig = {
headers: {
Accept: 'application/json',
mock: false,
'Content-Type': 'application/json',
},
data: reqBody,
method: 'POST',
url: `${config.app.entTokens.host}`, // need to get from env variables
timeout: config.app.enterpriseHTTPTimeout
};
try {
const token = await axios(httpSearchAddressUXConfig);
return token.data;
} catch (err) {
throw err;
}
I have following test case which fails with unhandled Promise rejection error
it('should find Jwt token ', async(done) => {
const actualTokenfound = jwtTokenService.getJwtToken();
return actualTokenfound
.then(result => expect(result).toBe(Object))
.then(done);
});
Any Suggestions ?
If you define a async function, you don't need to use "done". I guess something like this it'll works.
it('should find Jwt token ', async () => {
const actualTokenfound = await jwtTokenService.getJwtToken();
expect(result).toBe(Object));
});
I have an array, said arr, and I need to iterate on it.
What I tried so far :
arr.forEach((rack) => {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'https://example.com/render',
body: "target=foobar"
}, function(error, response, data){
if (error) {
console.err(error);
} else {
console.log(JSON.stringify(data, null, 4));
}
});
});
I have no output, nor error.
Bonus question: Can I return a value from within the post in the global scope ?
forEach is strictly synchronous and is generally obsolete because it doesn't support generators and async..await while loop statements do. This can be done with async..await and request-promise, which is official promisified counterpart to request:
// within async function
for (const rack of arr) {
try {
const data = await request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'https://example.com/render',
body: "target=foobar"
});
console.log(JSON.stringify(data, null, 4));
} catch (error) {
console.err(error);
}
}
Since requests don't depend on each other, they could be performed in parallel with Promise.all.
Can I return a value from within the post in the global scope ?
This is a special case of this infamous problem. A value from asynchronous call cannot be consumed in synchronous manner, this extends asynchronous control flow to all call stack, possibly up to entry point:
(async () => {
const result = await asyncFn();
})().catch(console.error)
The first part of your question is because request is asynchronous, you complete the forEach loop and exit before the call is complete.
As for the second part, you can use promises to basically await the result of your query. The code
function getPromise(url) {
return new Promise((resolve, reject) => {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'https://example.com/render',
body: "target=foobar"
}, function(error, response, data) {
if(error) {
reject(error)
} else {
resolve(JSON.stringify(data, null, 4))
}
})
})
}
var promiseArray = arr.map((rack) => getPromise(rack))
Promise.all(promiseArray).then((value) => {
console.log('I am done');
})
Would be what you want. You can assign back to the global scope value (though it's not recommended)
A solution would be to wrap it in a promise:
for rack of arr {
try {
const result = await new Promise((res, rej) => {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'https://example.com/render',
body: "target=foobar"
}, function(error, response, data){
if (error) {
rej(error);
console.err(error);
} else {
res(data);
}
});
});
console.log(JSON.stringify(result, null, 4));
} catch(err) {
console.log(err);
}
}
I am trying to wrap Ajax into a Bluebird promise wrapper, but am receiving:
Error: Unhandled rejection (stack trace here...)
wrapper1.js
let fetch = require('./wrapper2');
function requestWeb(type, url, data) {
return new Promise(function(resolve, reject) {
url = config.serverUrl + url.trim();
let options = {
type: type,
data: data ? JSON.stringify(data) : null,
dataType: 'json',
contentType: 'application/json',
crossDomain: true,
timeout: 15000,
xhrFields: { withCredentials: true }
};
fetch(url, options)
.then(data => {
resolve(data);
})
.catch(err => {
console.log('web api error: ' + err.message);
notify('Please check your interet connection');
reject(err);
});
});
}
wrapper2.js
import Promise from 'bluebird';
export default function(url, options) {
return new Promise(function(resolve, reject) {
$.ajax(url, options)
.done((result) => {
resolve(result);
})
.fail((xhr, err) => {
let proxy = new Error();
proxy.message = err || 'error is null';
proxy.name = 'ajax error';
reject(proxy);
});
});
}
Please note Bluebird requires different error object on reject().
I figured it out, BlueBird wants to warn you that a reject() call has been fired but you are not catching it. So I was using...
requestWeb(type, url, data).then((result)=>{});
So to fix, do one of two things: add the .catch() to the end of the call, or remove the reject(err) from the promise.
Consider this snippet
fetch(`http://${api.host}:${api.port}/user`)
.then(function(data) {
return data.json();
}, function(err) {
throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
}).then(function(eparkUser) {
for (var key in eparkUser) {
if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
user[key] = eparkUser[key];
}
}
done(null, user);
}, function(err) {
throw new Error(`Couldn't parse returned json: ${err.message}`);
}).catch(function(e) {
done(e);
});
Isn't throw supposed to break the chain and trigger .catch ? How to achieve this behaviour? Becauce now both throw are getting executed and I see message:
Error: Couldn't parse returned json: Couldn't fetch user data from server: request to http://localhost:3010/user failed and that not what I want.
P.S. fetch is npm node-fetch module
No, throw does not jump to catch. It does reject the promise, and all error handlers installed on it will be invoked. In your case, that's the error handler installed by the then call. Notice that .catch(handler) is just sugar for .then(null, handler).
Your current code works like
try {
try {
try {
var data = fetch(`http://${api.host}:${api.port}/user`)
} catch(err) {
throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
}
var eparkUser = data.json();
} catch(err) {
throw new Error(`Couldn't parse returned json: ${err.message}`);
}
for (var key in eparkUser) {
if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
user[key] = eparkUser[key];
}
}
done(null, user);
} catch(e) {
done(e);
}
To solve your problem, you'll need to nest your handlers, and install the JSON-parse-handler only on that particular promise:
fetch(`http://${api.host}:${api.port}/user`)
.then(function (data) {
return data.json()
.then(function (eparkUser) {
for (var key in eparkUser) {
if (eparkUser.hasOwnProperty(key) && !user.hasOwnProperty(key)) {
user[key] = eparkUser[key];
}
}
return user;
}, function(err) {
throw new Error(`Couldn't parse returned json: ${err.message}`);
});
}, function(err) {
throw new Error(`Couldn\'t fetch user data from server: ${err.message}`);
})
.then(done.bind(null, null), done);