How to read error messages from javascript error object - javascript

Could some one help me out on below question please :-)
I'm making a post call through redux action, which is below.
export const addEmployee = ({ firstName, surname, contactNumber, email }) => async dispatch => {
const payloadBody = JSON.stringify({ firstName, surname, contactNumber, email });
fetch('/api/users', {
method: 'POST',
body: payloadBody,
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
if (!response.ok) {
return response.text()
.then(text => {
throw Error(text)
});
} else {
dispatch(setAlert("New Employee added ", 'danger'));
}
})
.catch(error => {
console.log('>>> in CATCH block, error is =>', error);
console.log('>>> in CATCH block, error name is =>', error.name);
console.log('>>> in CATCH block, error message is =>', error.message);
let allKeys = Object.getOwnPropertyNames(error);
console.log(allKeys);
// const errors = [];
// Object.keys(error.message).forEach(key => {
// console.log('>>> key are ', key)
// })
// const keys = Object.keys(error.message);
// console.log(keys);
// const errors = error.message['errors'];
// const errors = error.response.data.errors;
// if (errors) {
// errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
// }
dispatch({
type: REGISTER_FAIL
});
})
}
Above post call on failure, returns body with error message, an example is below
{
"errors": [
{
"msg": "User already exist with email"
}
]
}
Question
What I'm trying to achieve is, to grab the errors[] and pass the error message through to a component, the trouble I have is accessing the error[] array within the returned array message. I'll describe below what I've attempted, it also can be seen in the redux action method I posted above.
Try-1
console.log('>>> in CATCH block, error is =>', error); yields just Error
Try-2
console.log('>>> in CATCH block, error name is =>', error.name); yields {"errors":[{"msg":"User already exist with email"}]} and the typeof this is string since I'm returning text() return response.text().then(text => { throw Error(text) })
Try-3
When I return as json() return response.json().then(text => { throw Error(text) })and console.log('>>> in CATCH block, error message is =>', error.message); yields object.
The questions again What I'm trying to achieve is, to grab the errors[] and pass the error message through to a component such as below
const errors = error.message; // this is where I'd like to extract the error.
if (errors) {
errors.forEach(error => dispatch(setAlert(error.msg, 'danger')));
}
Hope the above description is clear, please let me know if you require more info,
I know I'm missing some crucial knowledge of working with error objects, could someone please shed some light on this please :-)

Pattern for throwing errors recovered from standard-format HTTP payload
Your redux action does work over HTTP. Sometimes the server responds with bad news, and it seems like there's a standardized format the server uses to report that news. Also, sometimes your own code throws. You want to handle both kinds of problem with control structures related to Errors.
Basic pattern for an async Redux action
Before we start: your action is marked async, but you're still chaining .then and .catch. Let's switch to async/await, converting this:
export const addEmployee = (/*...*/) = async ( dispatch, getState ) => {
fetch(/* ... */)
.then(response => {
return response.text()
.then(text => {
// happy-path logic
throw Error(text)
})
})
.catch(error => {
// sad-path logic
dispatch(/* ... */)
})
}
...into this:
export const addEmployee = (/*...*/) = async ( dispatch, getState ) => {
try {
let response = await fetch(/* ... */)
let responseText = await response.text()
// happy-path logic
dispatch(/* ... */)
return // a redux action should return something meaningful
} catch ( error ) {
// sad-path logic
dispatch(/* ... */)
return // a failed redux action should also return something meaningful
}
}
Now let's talk about errors.
Error basics
Meet throw:
try { throw 'mud' } catch( exception ) { /* exception === 'mud' */ }
try { throw 5 } catch( exception ) { /* exception === 5 */ }
try { throw new Date() } catch( exception ) { /* exception is a Date */ }
You can throw just about anything. When you do, execution halts and immediately jumps to the closest catch, searching all the way through the stack until it finds one or runs out of stack. Wherever it lands, the value you provided to throw becomes the argument received by catch (known as an "exception"). If nothing catches it, your JS console logs it as an "uncaught exception."
You can throw anything, but what should you throw? I think you should only throw instances of Error, or one of its subclasses. The two main reasons are that the Error class does some helpful things (like capturing a stacktrace), and because one of your two sources of failure is already going to be throwing Error instances, so you must do something similar if you wish to handle both with a single codepath.
Meet Error:
try {
throw new Error('bad news')
} catch ( error ) {
console.log(error.message)
//> 'bad news'
}
We already know that an Error will be thrown if code within your action blows up, e.g. JSON.parse fails on the response body, So we don't have to do anything special to direct execution onto the catch path in those scenarios.
The only thing we have to be responsible for is to check whether the HTTP response contains something that looks like your server's "standard error payload" (more on that later), which your sample suggests is this:
{
"errors": [
{
"msg": "ERROR CONTENT HERE"
}
]
}
Here's the core issue
This handling has to be special because no javascript engine considers it an error simply to receive an HTTP payload that can be parsed as JSON and which contains a key named "errors". (Nor should they.) This payload pattern is merely a custom convention used by some or all of the HTTP endpoints that you talk to.
That's not to say it's a bad idea. (I think it's great!) But that explains why it must be done custom: because this pattern is just your private little thing, and not actually special in a way that would make browsers treat it the special way you want.
So here's our plan:
make the request, relying on try/catch to capture things thrown by our tools
if we get a response that seems bad:
examine the payload for an error encoded in the "standard format"; I call anything like this an "API error"
if we find an API error, we will create and throw our own Error, using the API error content as its message
if we don't find an API error, we'll treat the raw body text of the response as the error message
if we get a response that seems good:
dispatch the good news (and useful data) to the store
Here's what that looks like in code:
export const addEmployee = ({
firstName,
surname,
contactNumber,
email
}) => async ( dispatch, getState ) => {
const payloadBody = {
firstName,
surname,
contactNumber,
email
}
try {
// step 1
let response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payloadBody)
})
let responseText = await response.text()
if (!response.ok) {
// step 2
let errorString = getErrorMessageFromResponseBody(responseText)
throw new Error(errorString) // API errors get thrown here
}
// step 3
let responseJson = JSON.parse(responseText)
dispatch(setAlert('New Employee added', responseJson.user.name))
/*
A redux action should always returns something useful.
addEmployee might return the `user` object that was created.
*/
return responseJson.user
} catch ( error ) {
// all errors land here
dispatch({
type: REGISTER_FAIL,
message: error.message
})
/*
A failed redux action should always return something useful (unless you prefer to throw).
For now, we'll return the reason for the failure.
*/
return error.message
}
}
function getErrorMessageFromResponseBody( string ) {
let errorString = string
try {
let json = JSON.parse(string)
if(json.errors) {
errorString = json.errors[0].msg
}
} catch ( parseOrAccessError ) {}
return errorString
}
Here's what can be thrown to that catch block:
anything thrown by JSON.parse when applied to the arguments
anything thrown by fetch
if !response.ok, the whole response payload (or just an error message if the payload contains an API error)
Exception handling
How can you tell those different kinds of failure apart? Two ways:
Some failures throw specific subclasses of Error, which you can test for with error instanceof SomeErrorClass:
JSON.stringify throws a TypeError if it can't serialize its argument (if you have custom .toJSON anywhere, it can also throw anything that throws)
fetch throws a TypeError if it can't reach the internet
JSON.parse throws a SyntaxError if the string can't be parsed (if you use a custom reviver, those errors get thrown too)
Any instance of Error or its subclasses will have a .message; you can test that string for specific cases
How should you handle them?
If JSON.stringify blows up, it's because you wired your data wrong. In that case, you probably want to do something that will alert the developer that something is broken and help diagnose the issue:
console.error(error)
dispatch some failure action that includes the error.message
show a generic error message on-screen
If fetch throws, you could dispatch a failure that presents a "fix your wifi" warning to the user.
If JSON.parse throws, the server is melting down, and you should show a generic error message.
A little sophistication
Those are the basic mechanics, but now you confront a messy situation. Let's list some challenges:
You may have already noticed one problem: "no internet" will present the same way as "circular data": a thrown TypeError.
It turns out that the precise text of JSON.stringify errors depends on the actual value supplied to that function, so you can't do something like error.message === CONSTANT_STRINGIFY_ERROR_MESSAGE.
You may not have an exhaustive list of every msg value the server can send in an API error.
So how are you supposed to tell the difference between a problem reported by a sane server vs a client-side bug vs a broken server vs unusable user data?
First, I recommend creating a special class for API errors. This lets us detect server-reported problems in a reliable way. And it provides a decent place for the logic inside getErrorMessageFromResponseBody.
class APIError extends Error {}
APIError.fromResponseText = function ( responseText ) {
// TODO: paste entire impl of getErrorMessageFromResponseBody
let message = getErrorMessageFromResponseBody(responseText)
return new APIError(message)
}
Then, we can do:
// throwing
if (!response.ok) {
// step 2
throw APIError.fromResponseText(responseText)
}
// detecting
catch ( exception ) {
if(exception instanceof APIError) {
switch(APIError.message) {
case 'User already exist with email':
// special logic
break
case 'etc':
// ...
}
}
}
Second, when throwing your own errors, never provide a dynamic string as the message.
Error messages for sane people
Consider:
function add( x, y ) {
if(typeof x !== 'number')
throw new Error(x + ' is not a number')
if(typeof y !== 'number')
throw new Error(y + ' is not a number')
return x + y
}
Every time add is called with a different non-numeric x, the error.message will be different:
add('a', 1)
//> 'a is not a number'
add({ species: 'dog', name: 'Fido' }, 1)
//> '[object Object] is not a number'
The problem in both cases is that I've provided an unacceptable value for x, but the messages are different. That makes it unnecessarily hard to group those cases together at runtime. My example even makes it impossible to tell whether it's x or y that offends!
These troubles apply pretty generally to the errors you'll receive from native and library code. My advice is to not repeat them in your own code if you can avoid it.
The simplest remedy I've found is just to always use static strings for error messages, and put some thought into establishing conventions for yourself. Here's what I do.
There are generally two kinds of errors:
some value I wish to use is objectionable
some operation I attempted has failed
In the first case, the relevant info is:
which datapoint is bad; I call this the "topic"
why it is bad, in one word; I call this the "objection"
All error messages related to objectionable values ought to include both datapoints, and in a manner that is consistent enough to facilitate flow-control while remaining understandable by a human. And ideally you should be able to grep the codebase for the literal message to find every place that can throw the error (this helps enormously with maintenance).
Here is how I construct the messages:
[objection] [topic]
There is usually a discrete set of objections:
missing: value was not supplied
unknown: could not find value in DB & other "bad key" issues
unavailable: value is already taken (e.g. username)
forbidden: sometimes specific values are off-limits despite being otherwise fine (e.g. no user may have username "root")
invalid: heavily overused by dev community; treat as option of last resort; reserved exclusively for values that are of the wrong datatype or syntactically unacceptable (e.g. zipCode = '__!!#')
I supplement individual apps with more specialized objections as needed, but this set comes up in just about everything.
The topic is almost always the literal variable name as it appears within the code block that threw. To assist with debugging, I think it is very important not to transform the variable name in any way.
This system yields error messages like these:
'missing lastName'
'unknown userId'
'unavailable player_color'
'forbidden emailAddress'
'invalid x'
In the second case, for failed operations, there's usually just one datapoint: the name of the operation (plus the fact that it failed). I use this format:
[operation] failed
As a rule, operation is the routine exactly as invoked:
try {
await API.updateUserProfile(newData)
} catch( error ) {
// can fail if service is down
if(error instanceof TypeError)
throw new Error('API.updateUserProfile failed')
}
This isn't the only way to keep your errors straight, but this set of conventions does make it easy to write new error code without having to think very hard, react intelligently to exceptions, and locate the sources of most errors that can be thrown.
Handling server inconsistencies
A final topic: it's pretty common for a server to be inconsistent about how it structures its payloads, particularly with errors but also with successes.
Very often, two endpoints will encode their errors using slightly different envelopes. Sometimes a single endpoint will use different envelopes for different failure cases. This is not usually deliberate, but it is often a reality.
You should coerce all the different flavors of server complaint into a single interface before any of this madness can leak into the rest of your application, and the shore of the client/server boundary is the best place to immediatley jettison server weirdness. If you let that stuff escape into the rest of your app, not only will it drive you insane, but it will make you brittle by allowing the server to surface errors deep inside your app, far away from the real source: a violated API contract.
A way to support a variety of envelopes is by adding extra code to getErrorMessageFromResponseBody for each of the different envelopes:
function getErrorMessageFromResponseBody( string ) {
let errorString = string
/*
"Format A"
{ errors: [{ msg: 'MESSAGE' }] }
used by most endpoints
*/
try { /*... */ } catch ( parseOrAccessError ) {}
/*
"Format B"
{ error: { message: 'MESSAGE' } }
used by legacy TPS endpoint
*/
try { /*... */ } catch ( parseOrAccessError ) {}
/*
"Format C"
{ e: CODE }
used by bandwidth-limited vendor X
use lookup table to convert CODE to a readable string
*/
try { /*... */ } catch ( parseOrAccessError ) {}
return errorString
}
One of the values of having a dedicated APIError class to wrap these things is that the class constructor provides a natural way to gather all this up.

Related

Firebase - How to extend FirebaseError?

I am implementing a cloud function for signing up with unique username and password.
In order to throw exceptions, I was previously doing the following:
signUpValidation.js
if (!validateUsername(username)) {
throw new functions.https.HttpsError(
"invalid-argument",
"Invalid username.",
{
status: "error",
code: "auth/invalid-username",
message: "Username must be between 3 and 30 characters, including numbers, letters, hyphens, periods, or underscores.",
}
);
}
signUp.function.js
try {
await validateSignUpData(
username,
email,
password,
repeatPassword,
name,
birthday,
clientIp
);
} catch(err) {
if (err instanceof functions.https.HttpsError) {
throw err;
}
// An unknown error has occurred
console.error(err);
throw new functions.https.HttpsError(
"unknown",
"Unexpected error.",
{
status: "error",
code: err.code ?? "unknown",
message: err.message ?? "The registration request could not be processed. Please, try again later."
}
);
}
But, I don't really like this way of throwing the exceptions in the signUpValidation module... it makes more sense to me to throw "AuthErrors" instead of "HttpsErrors".
So, as it seems not possible to extend the default Firebase Errors, I have decided to create my own util/authErrors module:
class AuthError extends Error {
constructor(code, message) {
super(message);
this.code = code;
this.name = "AuthError";
}
}
const authErrors = Object.freeze({
usernameAlreadyExists(message = "The username is already in use by an existing account") {
return new AuthError('auth/email-already-exists', message);
}
... more errors
});
module.exports = authErrors;
as you can see, I have created my custom Error and some factory functions for every error type. Then, in my signUpValidation.js, I just do:
if (!(await isUsernameUnique(username))) {
throw authErrors.usernameAlreadyExists();
}
Is it possible to extend a FirebaseError? If not, why?
Is it considered a bad practice to work this way in order to throw custom exceptions in Cloud Functions? I mean, should I just throw HttpsErrors?
Having Custom Error Type is useful if you are going to treat it differently.
For example if you have a try/catch block and want to have a different logic for your custom error.
but here you are passing error to client which has no idea of either Firebase HttpsError or your custom AuthError. because at the end your object will be serialized to JSON and at the other end there is no class to convert it back to HttpsError or AuthError.
Also at HTTP protocol level, authentication errors are defined by HTTP status codes (e.g. 401 ,403) so they are not inherently different object types.
What I'm saying is that I don't see any advantage in having a custom AuthError class on your server side when it can not be transformed as it is to your client to be treated differently.
For client the HTTP status code is the key to differentiate an Auth error from other type of errors.

Is there a functional difference between these 2 snippets of my code? Does the second one handle possible errors the same way as the first?

I asked a question on stack overflow earlier, and a kind user suggested some improvements for my code which seemed great, so I started going over my code in order to implement these changes. The problem is that I'm not sure if my reworked code is handling possible errors the same way as the first.
Here's my current code right now:
module.exports.deleteBrand = async (req, res, next) => {
let brandId = req.body.brandId
let brand
try {
brand = await Brand.destroy({
where: {
id: brandId
}
})
} catch (e) {
console.log(e)
}
if (brand) {
res.status(200).json({
brand: brand
})
} else {
res.status(500)
}
}
And this is how I intend to rework it:
module.exports.deleteBrand = async (req, res, next) => {
let brandId = req.body.brandId
try {
let brand = await Brand.destroy({
where: {
id: brandId
}
})
res.status(200).json({
brand: brand
})
} catch (e) {
console.log(e)
res.status(500)
}
}
As you can see, in my first code snippet, the try-catch block surrounds only my database query and then I check if the database query was successful outside the try-catch, and only send the 200 status response if it is. Otherwise, I send a 500 status.
Is my if-else useless in that scenario, considering that if the database query fails, the error would be caught by the catch block? Should the code that returns 500 status be placed in the catch block?
There is a small difference in error handling, yes, but if anything it seems likely to be an improvement. The difference is:
In your first example, an error raised by res.status(200).json({brand: brand}) after successfully retrieving brand from the database is not caught and terminates deleteBrand.
In your second example, that error is caught and results in calling the res.status(500) in the catch block.
json({brand: brand}) might throw an error if brand has any circular references and so can't be converted to JSON. In that case, your res.status(500) will overwrite your previous res.status(200) (assuming response headers haven't been sent yet, which is probably a correct assumption).
Side note: You're using ES2015+ code, which means you can use shorthand property notation and change .json({brand: brand}) to simply .json({brand}).

Can We Explicitly Catch Puppeteer (Chrome/Chromium) Error net::ERR_ABORTED?

Can we explicitly and specifically catch Puppeteer (Chromme/Chromium) error net::ERR_ABORTED? Or is string matching the only option currently?
page.goto(oneClickAuthPage).catch(e => {
if (e.message.includes('net::ERR_ABORTED')) {}
})
/* "net::ERROR_ABORTED" occurs for sub-resources on a page if we navigate
* away too quickly. I'm specifically awaiting a 302 response for successful
* login and then immediately navigating to the auth-protected page.
*/
await page.waitForResponse(res => res.url() === href && res.status() === 302)
page.goto(originalRequestPage)
Ideally, this would be similar to a potential event we could catch with page.on('requestaborted')
I'd recommend putting your api calls and so in a trycatch block
If it fails, you catch the error, like you are currently doing. But it just looks a bit nicer
try {
await page.goto(PAGE)
} catch(error) {
console.log(error) or console.error(error)
//do specific functionality based on error codes
if(error.status === 300) {
//I don't know what app you are building this in
//But if it's in React, here you could do
//setState to display error messages and so forth
setError('Action aborted')
//if it's in an express app, you can respond with your own data
res.send({error: 'Action aborted'})
}
}
If there are not specific error codes in the error responses for when Puppeteer is aborted, it means that Puppeteer's API has not been coded to return data like that, unfortunately :')
It's not too uncommon to do error messages checks like you are doing in your question. It's, unfortunately, the only way we can do it, since this is what we're given to work with :'P

fetch returns SyntaxError: Unexpected token T in JSON at position 0

I'm trying to use the Javascript fetch method, however, it does not seem to work asynchronously.
Here's my code:
fetch(`${global.URL}${url}`, requestConfig)
.then(res => res.json())
.then(res => {
console.log('response', res);
return res;
})
.catch(error => {
console.log('error: ', error)
})
I get the following error 70% of the time, then the other 30%, a valid response is received, when I save the file and it re-renders, it sometimes works.
error: SyntaxError: Unexpected token T in JSON at position 0
at parse (<anonymous>)
at tryCallOne (core.js:37)
at core.js:123
at JSTimers.js:277
at _callTimer (JSTimers.js:135)
at _callImmediatesPass (JSTimers.js:183)
at Object.callImmediates (JSTimers.js:446)
at MessageQueue.__callImmediates (MessageQueue.js:396)
at MessageQueue.js:144
at MessageQueue.__guard (MessageQueue.js:373)
I've tried calling it inside and async/await function but it does not help.
EDIT 1:
this is how I make my requests
const authenticityToken = global.TOKEN
const query = (url, config) => {
const requestConfig = {
credentials: 'same-origin',
...config,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json',
Accept: 'application/json',
Authorization: authenticityToken,
},
}
return fetch(`${global.URL}${url}`, requestConfig)
.then(res => res.json())
.then(res => {
console.log('response', res);
return res;
})
.catch(error => {
console.log('error: ', error)
})
// .then(handleResponseError)
}
export const get = (url, data) =>
query(data ? `${url}?${stringify(data)}` : url)
export function fetchUser() {
return (
get('/api/v3/me/')
)
}
Then I call the function inside my component like so:
const fetchUserAction = () => {
fetchUser()
.then((response) => {
if(response) setUser(response.data)
})
}
useEffect(() => {
fetchUserAction()
}, [])
This type of error usually happens when your server returns something which is not JSON. In my experience, 99% of the time the server is returning a generic error message. Often times servers will have a generic "catch all" error handler which returns something like:
There was an error processing your request.
In this case, if you tried to use JSON.parse (or res.json() in your case), you would get the error you are experiencing. To see this, paste this into your console:
JSON.parse("There was an error processing your request.")
//-> Uncaught SyntaxError: Unexpected token T in JSON at position 0
Solution 1: Usually the server will set a proper status code whenever there is an error. Check to make sure the response status is 200 before parsing:
fetch('...').then(res => {
if (res.status !== 200) {
throw new Error(`There was an error with status code ${res.status}`)
}
return res.json()
)
Solution 2: Update your server code to return an error message in JSON format. If you're using node and express, this would look something like this:
function errorHandler (err, req, res, next) {
if (res.headersSent) return next(err)
const message = 'There was an error processing your request.'
res.status(500)
if (req.accepts('json')) {
// The request contains the "Accept" header with the value "application/json"
res.send({ error: message });
return;
}
res.send(message);
}
Then, you would update your frontend code accordingly:
fetch('...')
.then(res => res.json())
.then(res => {
if (res.error) {
throw new Error(res.error)
}
return res
)
This kind of error Unexpected token T in JSON at position 0 always happens when the string you are trying to parse cannot be parsed as JSON. This specific error means that the string starts with the character 'T' and not with a '{' as strings that can be parsed to JSON should start. There's a very strict format that allows your string to become an object.
This is probably not the problem if you made sure on the backend that your code takes an object, stringifies it, and sends the text. If you know that on the backend the only thing that can be sent is a stringified object, there is probably nothing wrong there.
The second more plausible answer is that your request failed, I see you prepared a catch block in case the request returns an error, but there's a problem there. The request could have failed for several reasons, if you say it happens only some of the time it is probably CORS problems or a logical bug on the backend. In that case, you would like to see the response itself and not an already parsed response. What essentially happens is that when your request succeeds the body is successfully parsed to an object and everything works fine, but when the request fails, the response would be an exception that starts with a T, for example, a TimeoutException that when you try to parse it fails because it starts with a T and not as JSON. What you need to see is the response before it is parsed to JSON, and only if it is not an error, you should try to parse it.
The problem in your code is that the first thing you do is to try and parse it as JSON. I would suggest you comment out this line and simply print, either the successful request or the failed request as strings. I'm pretty sure you will find that in 70% of the time, you will see the JSON string that you expected and in the remaining 30, you will get an exception string (that might be even thrown automatically by your backend hosting service, like Timeout exceptions, they might not be treated as errors but as strings. This, unfortunately, happens a lot on the free plan of Firebase functions where the time a function is running is limited to a certain number of seconds, you should check it in the plans' description on their website) that starts with a T. This will most certainly help you find where the problem is by giving you more information.
On another note, I warmly recommend you to stop using then and catch and instead start using the far superior async/await syntax that helps you keep your code simple and organized. If it's compatible with all the engines you are targeting, read the Mozilla documentation about it, it's pretty straightforward: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Have a nice day and happy coding

Flow control with async without throwing Errors

I am having an issue where Intellij is warning me about 'throw' of exception caught locally. After doing some digging on why this is not ok it makes sense, errors should not be used for flow control. The problem I am facing though is in async I cannot reject the promise without throw something locally and I get the warning.
Some of my example code.
Top level takes in the request and awaits for the response from the controller:
Router.post("/", async (req, res) => {
try {
let itemController = new ItemController(req.body);
let response = await itemController.request();
res.send(response);
} catch (error) {
res.status(500).send({ error: error});
}
});
The controller takes in the request and awaits on other functions to get some data.
async request() {
try {
await isValidItem();
return await this.initialize();
} catch(error) {
throw error;
}
}
Then I have a function which gets manufacturer ID for this item and I run into my problem. If the SQL query doesn't fail and nothing is in the response I need to throw a local error so that the request can fail gracefully. and send a proper 500 error to the client.
async queryManufacturerID() {
try {
let result = await this.queryManufacturerID(this.itemID, this.brand);
if (result === false) {
throw new Error("this item has no manufacturer ID");
} else {
this.manufacturerID = result["manufacturerItemID"];
}
} catch (error) {
throw error;
}
}
My problem is I know I can adjust this so other functions that get a reply from this can know that this function failed without a error but that would have to happen in this entire chain to prevent throwing locally. Seems like a lot of bloat.
The only thing that makes this code bloaty and the IDE complain is not throwing errors, but this:
try {
//...
} catch (error) {
throw error;
}
It's a no op. You can safely remove it without changing the logic.
The only case where you should use catch is when you actually plan to handle the error and get the execution back on track.
After doing some digging on why this is not ok it makes sense, errors should not be used for flow control
I disagree. Errors are a part of proper flow control, they allow you to handle unplanned things. Throwing an error if something unexpected occured makes sense, also in this case.

Categories

Resources