I am using a node route and I use a trycatch block but Node.js is not having it. When there is an error with the code and it goes to the catch, it fails.
try {
...
res.send({ message: 'All good nothing wrong with the code above' })
} catch {
res.status(500).send({ message: 'There is an error I want to send to the front end' })
}
Node clearly is not happy about this, I know I cannot send res.send()twice but it is on a trycatch block. How do I send an error message back the front end if something fails?
Node complains with on the catch block:
'Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client'
UPDATE
I fixed it by sending the error object with throw to the catch block and not to use res.send() on the try catch for any conditional other than just once
It is always good to terminate the execution flow of the function when you want to send something and not do anything else afterwards.
res.send('All ok');
console.log('Response sent');
return;
or
return res.send('All ok');
try {
throw Error('Oops')
return res.send('OK')
} catch(error) {
return res.send('Not OK: ' + error.message)
}
You can't use two times res.send so add return.
try {
...
} catch {
res.status(500).send({ message: 'There is an error I want to send to the front end' })
return;
}
res.send({ message: 'All good nothing wrong with the code above' })
Related
I am creating a NodeJS API using Express, PostgreSQL in which I created a controller function which will check the user from the database.
const checkUser = async (req, res) => {
try {
const user = await pool.query('select * from users where email = $1', [req.body.email]);
if (user.rows.length === 0) throw new Error('Error Found');
return res.json("User Found");
} catch (e) {
//======= Output at console ========
//Error: Error Found
console.log(e);
//======== Response Object Received From API ==========
// {
// "msg": "Error Found",
// "Error": {}
// }
res.status(400).send({ msg: 'Error Found', Error: e });
}
};
Consider the situation that the user is not found in the Database so from try block the control passes to the catch block.
1- I am not able to get why the Error thrown from the try block to catch block sends back an empty object as a response. Also, at the same time using console.log prints the correct output value in the console.
2- I want a fix so that I can send e as a response to the User.
The problem is that Error objects are not that easy to serialize (which is intentional). This...
try {
throw new Error('Catch me if you can');
} catch(e) {
console.log(JSON.stringify(e)); // {}
}
... just logs {}, the same as for empty object, because Error objects don't have enumerable properties. And in your case, you don't send that object directly - but make it a property of another object sent to client.
However, there are several ways out of this. If you always need your client to get all the details of an Error, cast that to string (as toString() is overridden):
try {
throw new Error('Catch me if you can');
} catch(e) {
console.log(JSON.stringify(e.toString())); // "Error: Catch me if you can"
}
... or use Error object properties - name and message - as separate fields of your response:
res.status(400).send({
name: e.name || 'Anonymous Error',
msg: e.message || 'no message provided'
});
As sub-approach, you might consider choosing your status code based on type of error you have (always sending 404 for 'not founds', for example).
Sup guys! This is the code on server side when something goes wrong:
return res.status(400).send({ error: 'Email already used!'});
And this is my frontend code that I try to catch the error message:
return async dispacth => {
try {
const res = await axios.post('http://localhost:3333/account/signin', userData);
localStorage.setItem('JWT_TOKEN', res.data.token);
dispacth({
type: AUTH_SIGN_IN,
token: res.data.token
});
} catch (err) {
console.log(err.message)
console.error('error', err);
dispacth({
type: AUTH_ERROR,
errorMessage: err.message
});
}
}
But this is what I got on browser's console:
Try console.log(err.response) instead of console.log(err.message).
I'm new to Node and Axios, but using "err.response" after catching "err" fixed a very similar issue I had.
For res.status(400).send('Email already used!');
You could do:
console.log(error.response.data.message);
For the error message being sent as a JSON object like res.status(400).send({ error: 'Email already used!'});
You could do:
console.log(error.response.data.error);
The sequelize create statement has an error and I would like to handle that error. Since the create statement has the error I need to handle promise rejection. How do I do that in code? Tried to look at the sequelize documents but unable to work it out.
db.Employee.create(empData,
{
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
return next(err);
});
The error is on the create and so the webpage just gives an internal server error. I was under the impression that the catch was something that handled the promise rejection and failure. In this case, how can I handle the promise rejection in code. An example would be greatly appreciated.
By doing next(err), by default, you send a 500 Internal Server Error message. If you use Express, and want to show a custom error, just append a status code which is not 5xx to the error:
General Usage:
const err = new Error("my custom error")
err.statusCode = 400
next(err)
In your snippet, do:
db.Employee.create(empData, {
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
err.statusCode = 400
next(err);
});
If you haven't set your error handler in Express you will need to add somewhere at the end of the main file this:
// Error Handler
app.use(function(err, req, res, next) {
console.error(err)
if (!err.statusCode) err.statusCode = 500;
let msg = err.message
// Do not expose 500 error messages in production, to the client
if (process.env.NODE_ENV === "production" && err.statusCode === 500) {
msg = "Internal Server Error"
}
res.status(err.statusCode).send(msg)
})
Your webpage showing a 500 error means the issue was caught / working as intended. What you need to do is figure out how to handle displaying that error in a pretty format - this being a UI task. If you want a 'patch' for hiding the issue, change your return to a res. This will trick your browser with a 200 status and hide the error.
I do want to add, I recommend trying async/await for sequelize. There's a good amount of usage examples with it.
Promise
db.Employee.create(empData,
{
include:[
{
model: db.EmployeeDetails
}
]
}).then(function(newEmployee){
res.json(newEmployee);
}).catch(function(err){
// Temporary patch
res.json("pretty error message");
});
Async/Await version
async function createEmployee(empData) {
try {
return await db.Employee.create(empData, {
include:[ { model: db.EmployeeDetails } ]
});
} catch (err) {
// Handle error here
return err;
}
}
I'm using react in front end. Why cant I read data/message sent by the express when the status code is 409 or any 400 status code?
This is how I'm trying to read the response
hSubmit = event => {
console.log(this.state.checklistName)
event.preventDefault();
post.AddChecklistNames(this.state.token,this.state.category,this.state.checklistName)
.then(res=> {
if(res.status===201){
// window.location.reload(true);
}
else if(res.status===400||res.status===409||res.status===401||res.status===404||res.status===403){
console.log(res)
window.alert(res.data.error)
}
this.setState({checklistName:""})
})
What express is sending
response.status(409).json({ error: 'there is conflict'})
I can't read the error
res is not defined i guess. Try this:
.then(res=> {
if(res.status===201){
// window.location.reload(true);
})
.catch (err) {
console.log(err.response.data)
window.alert(err.response.data)
}
When returning error status code, response is treated as an error, so you should check error.response.data in a catch block
You need to catch error in catch block. In catch block you can see your error response and implement your logic accordingly
in the following code, i created an error
db.collection('deals').findOne({"_id":"8976889"})
.then(function(dealsInfoResult){
throw Error("THIS IS THE ERROR");
return (dealsInfoResult);
})
.catch(function(err){
console.log("ERRRR: " + err);
res.send(err);
})
});
after the error occurs, err does not have any error message, its empty. Rather "Error: This is the Error" is printed
In case of any error, i want the error to be stored in err so that i can handle it in my way.
Use err.message to see the string.