NodeJS use errors for specific cases - javascript

Im using the following function that works ok, However I have some issue with the error handling
e.g.
I want to catch generic error for all the functions
If fn1 or fn2 returns any error the function should throw 'generic error occurred`
Here is the what I need
if getData2 doesn’t have specific property value (see the if) return a uniq error uniq error occurred and not the general error...
This is working example
https://jsfiddle.net/8duz7n23/
async function func1() {
try {
const data = await getData1()
console.log(data)
const data2 = await getData2();
if (!data2.url === !"https://test2.com") {
throw new Error("uniq error occurred ")
}
return data2.url
} catch (e) {
throw new Error("generic error occurred ")
}
}
async function getData1() {
return "something"
}
async function getData2() {
return {
url: "http://test.com"
}
}
func1().then(result => {
console.log(result);
}).catch(error => {
console.log(error);
});
Now If I throw the uniq error the catch will throw the general error.
I want that in case func2 will have some error it still throw away
a general error but just if doenst have the right url,
trow all the way up the uniq error ...
Is there any cleaner way to do it in nodejs?
I dont want to use an if statement for messages in the catch etc...
I want that the will thrown to the upper level function and not to the catch

In order to propagate error to the "upper level", you should have to throw it again in catch block.
You can add your custom error type and check if the error is what you're looking for or not.
class UrlMismatchError extends Error {
name="UrlMismatchError"
}
async function func1() {
try {
const data = await getData1()
console.log(data)
const data2 = await getData2();
if (data2.url !== "https://test2.com") {
throw new UrlMismatchError("uniq error occured");
}
return data2.url
} catch (e) {
if (e instanceof UrlMismatchError) {
throw e;
} else {
// handle generic errors
throw new Error("generic error occured");
}
}
}
async function getData1() {
return "something"
}
async function getData2() {
return {
url: "http://test.com"
}
}
func1().then(result => {
console.log(result);
}).catch(error => {
console.error(error.message);
});
I dont want to use an if statement for messages in the catch etc...
I want that the will thrown to the upper level function and not to the catch
No you cannot do that, because javascript is not java, so you cannot do such thing as the follows:
// the code snippet below wont work
try {
doSomething();
} catch(UrlMismatchError e) {
// propagate error to the upper level
throw e;
} catch(Error e) {
// handle all the other errors
console.log(e);
}

Related

What is the difference between throw Error(error) and throw error

What is the difference between:
try {
const result = await hello();
} catch (error) {
throw error;
}
and
try {
const result = await hello();
} catch (error) {
throw Error(error);
}
Also
Is the second one necessary? It seems like you are just wrapping an error with an Error Object. Which one is preferred? Please help me understand.
It's possible that the value that the Promise rejected with was not an error object, but something else:
(async() => {
try {
const result = await Promise.reject(5);
} catch (error) {
console.log(error);
console.log(typeof error);
}
})();
Doing
throw Error(error);
makes sure that the value being thrown is definitely an Error object, which could be important if the thrown value is examined later and is expected to be such an object. You wouldn't want, for example, for undefined or null to be thrown (strange, I know, but not impossible) and for accessing a property of that to then throw at the point where you're catching for real.
const hello = () => new Promise((resolve, reject) => {
reject();
});
(async() => {
try {
const result = await hello();
} catch (error) {
throw error;
}
})()
.catch((error) => {
console.log('The error message was:');
console.log(error.message);
});

How to throw out of then-catch block?

I am currently figuring out how to throw an Exception out of a then catch block. I want to get into the catch that is inside the errorHandler() function.
const errorHandler = function () {
try {
thisFunctionReturnsAnError().then(response => {
console.log(response);
});
} catch (e) {
console.log(e); //How to trigger this?
}
};
const thisFunctionReturnsAnError = function () {
return3()
.then(value => {
throw new Error('This is the error message.');
})
.catch(err => {
//return Promise.reject('this will get rejected');
throw err;
//this one should somehow got to the catch that is located in the errorHandler() function. How to do this?
//I know that this 'err' will be in the next catch block that is written here. This is not what i want.
});
};
const return3 = async function () {
return 3;
};
errorHandler();
I searched a while on stackoverflow but nothing helped me. I am sure that this question got asked often but I could not find the answer, sorry for that.
EDIT:
added here another version of the code but it still does not work
const errorHandler = async function () {
try {
thisFunctionReturnsAnError()
.then(response => console.log(response))
.catch(err => console.log(err));
} catch (e) {
//console.log(e); //How to trigger this?
}
};
const thisFunctionReturnsAnError = function () {
return3()
.then(value => {
throw new Error('This is the error message.');
})
.catch(err => {
return Promise.reject(`Message is: ${err}`);
});
};
const return3 = async function () {
return 3;
};
errorHandler();
I will get the following error message:
Uncaught (in promise) Message is: Error: This is the error message.
Your code can't be executed, because "thisFunctionReturnsAnError" is not returning an Promise. That means that you can't call "then" on the return value.
thisFunctionReturnsAnError().then(response => { // will not work
Why not always use a promise?
const errorHandler = function () {
thisFunctionReturnsAnError()
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log('errorHandler: Handle the error.');
});
};
const thisFunctionReturnsAnError = function () {
return return_Three()
.then((value) => {
throw new Error('This is the error message.');
})
.catch((err) => {
//return Promise.reject('this will get rejected');
throw err;
//this one should somehow got to the catch that is located in the errorHandler() function. How to do this?
//I know that this 'err' will be in the next catch block that is written here. This is not what i want.
});
};
const return_Three = async function () {
return 3;
};
errorHandler();
/*****JUST ANOTHER SYNTAX*******/
const secondErrorHandler = async function () {
try {
await thisFunctionReturnsAnError();
} catch (error) {
console.log('secondErrorHandler: Handle the error.');
}
};
secondErrorHandler();
You cannot handle promise rejections with synchronous try/catch. Don't use it, use the promise .catch() method like in your thisFunctionReturnsAnError function.
You can handle promise rejections with try/catch when using async/await syntax (which you already do, albeit unnecessarily, in return3):
async function errorHandler() { /*
^^^^^ */
try {
const response = await thisFunctionReturnsAnError();
// ^^^^^
console.log(response);
} catch (e) {
console.log(e); // works
}
}

How to return error from asynchronous call

I have a function written in a file.
async myfunction() {
try {
const data = await achievementService.stepsPerDayAchievement()
console.log(data)
} catch(err) {
console.log(err)
}
}
I call another function from here which is written in another file called achievement.
async stepsPerDayAchievement(user, stepsCount) {
try {
await ApiCall()
} catch (err) {
return err
}
}
But when I return err from this function it suppose it as function return and I get the error in data. What I need here is when I throw error from
the stepsPerDayAchievement function it goes to the error part in my first file of function
Can someone please help what I am doing wrong here
You need to throw an error from the stepsPerDayAchievement method:
async stepsPerDayAchievement(user, stepsCount) {
try {
await ApiCall()
} catch (err) {
throw new Error(err);
}
}
this way it will land in the catch block of the calling function.
Since async functions return promises you don't need try catch block in stepsPerDayAchievement function. I think your code should be like below:
async myfunction() {
const data = await achievementService.stepsPerDayAchievement()
.then(()=> console.log(data);)
.catch(()=> console.err("error");)
}
async stepsPerDayAchievement(user, stepsCount) {
var apiCallResultData = await ApiCall();
return apiCallResultData
}

Throw custom errors async/await try-catch

Let's say I have a function like this -
doSomeOperation = async () => {
try {
let result = await DoSomething.mightCauseException();
if (result.invalidState) {
throw new Error("Invalid State error");
}
return result;
} catch (error) {
ExceptionLogger.log(error);
throw new Error("Error performing operation");
}
};
Here the DoSomething.mightCauseException is an asynchronous call that might cause an exception and I'm using try..catch to handle it. But then using the result obtained, I might decide that I need to tell the caller of doSomeOperation that the operation has failed with a certain reason.
In the above function, the Error I'm throwing is caught by the catch block and only a generic Error gets thrown back to the caller of doSomeOperation.
Caller of doSomeOperation might be doing something like this -
doSomeOperation()
.then((result) => console.log("Success"))
.catch((error) => console.log("Failed", error.message))
My custom error never gets here.
This pattern can be used when building Express apps. The route handler would call some function which might want to fail in different ways and let the client know why it failed.
I'm wondering how this can be done? Is there any other pattern to follow here? Thanks!
Just change the order of your lines.
doSomeOperation = async() => {
let result = false;
try {
result = await DoSomething.mightCauseException();
} catch (error) {
ExceptionLogger.log(error);
throw new Error("Error performing operation");
}
if (!result || result.invalidState) {
throw new Error("Invalid State error");
}
return result;
};
Update 1
Or you could create custom errors as below.
class MyError extends Error {
constructor(m) {
super(m);
}
}
function x() {
try {
throw new MyError("Wasted");
} catch (err) {
if (err instanceof MyError) {
throw err;
} else {
throw new Error("Bummer");
}
}
}
x();
Update 2
Mapping this to your case,
class MyError extends Error {
constructor(m) {
super(m);
}
}
doSomeOperation = async() => {
try {
let result = await mightCauseException();
if (result.invalidState) {
throw new MyError("Invalid State error");
}
return result;
} catch (error) {
if (error instanceof MyError) {
throw error;
}
throw new Error("Error performing operation");
}
};
async function mightCauseException() {
let random = Math.floor(Math.random() * 1000);
if (random % 3 === 0) {
return {
invalidState: true
}
} else if (random % 3 === 1) {
return {
invalidState: false
}
} else {
throw Error("Error from function");
}
}
doSomeOperation()
.then((result) => console.log("Success"))
.catch((error) => console.log("Failed", error.message))
You can simply use throw instead of using Error constructor
const doSomeOperation = async () => {
try {
throw {customError:"just throw only "}
} catch (error) {
console.log(error)
}
};
doSomeOperation()

Try-catch-rethrow - proper pattern

If I have such code:
let result;
try {
result = doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
// do something with result if didn't throw
Is this valid pattern in JS? I don't like using let. I prefer const but I can't use it in this case because it won't be available outside try-catch block.
I could put whole code in try block and get rid of let but then it would be harder to read in my opinion:
try {
const result = doSomethingThatCanThrow();
// do something with result if didn't throw
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
Keep it mind that it can always grow.
Also I could always skip rethrowing but I want to add some more information to error.
Which option is better and why? Are there any other possibilities?
You can utilize finally
(async(doSomethingThatCanThrow) => {
let result;
try {
result = await doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
} finally {
if (result !== undefined) {
// do something with result if didn't throw
console.log(result);
} else {
console.log(result);
}
}
// do stuff
})(() => Promise.reject(123))
.catch(err => console.error(err));
Try a test condition to see if the variable result is empty, or not!
var result
try {
result = "This time it worked!";
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`)
}
if (result) {
console.log(result)
}
var result
try {
} catch (e) {
}
// do something with result if didn't throw
if (!result) {
// var result undefined
// Result not thrown!
console.log("Failed")
}
In this case, I think the only real way to avoid let (other than using var as another response suggested - don't do that), is to extract this try-catch into a function and return the result directly with the try block, i.e.
const doSomethingThatCanThrowAndRethrowWithUpdatedMessageIfFails = () => {
try {
return doSomethingThatCanThrow();
} catch (e) {
throw new Error(`Thrown error because <some info> ${e}`);
}
}
const result = doSomethingThatCanThrowAndRethrowWithUpdatedMessageIfFails();

Categories