This question already has answers here:
How to catch the server response, even if 400 bad request error occured?
(2 answers)
Closed 12 months ago.
I have a Nodejs server running that registers the users. On successful registration, it returns a status code of 200 and a JSON response. But on unsuccessful registration where the email already exists, it returns the status code of 400 and a JSON response.Now the problem is that I'm able to read the JSON of 200 responses but I'm not able to access the JSON of 400 responses. I am using axios to fetch the data from the server.
Code for the email that already exists
if (emailExists) {
return res.status(400).json({
success: false,
message: 'This email address is already being used.'
})
}
Response for a valid registration
return res.status(200).json({
success: true,
message: 'You are signed up successfully.',
})
Response on successful signup
Behaviour when the email is already being used
This is how I'm sending the request
With axios(), to handle a 400 error, you need to use a .catch() to catch the rejected promise and then examine the error object you get. So, in addition to your .then(), use a .catch():
axios(...).then((result) => {
console.log(result);
}).catch(err => {
console.log(err.response.status);
console.log(err.response.data);
});
Or, if you were using an await fetch(...), then surround that with a try/catch and catch the error in the catch block.
In your code ALL promises that can ever reject MUST have an error handler for the rejection. Since your console shows "uncaught (in promise) Error", that means you had no means of catching the rejected promise.
You can intercept the response before they are handled by then or catch. Example below:
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
Doc reference: https://axios-http.com/docs/interceptors
Related
I have a nodejs react app where I fetch some data to the server:
await fetch(`${process.env.NEXT_PUBLIC_DR_HOST}/validate`, {
method: 'POST',
body: valBody,
headers: { 'Content-Type': 'application/json' }
})
After that, the data will be validated to see if there are any errors within its content.
If everything is fine, a 200 status code is returned (manually or by default) back as response, and then something else should happen:
.then(res =>
{
console.log(res)
if (res.status === 200)
{
//do stuff
If there is an error, a 400 code will be sent
if (error)
{
const msg = error.details.map(e => e.message).join(',') //
res.status(400).send("Invalid Data")
throw new ServerError("Invalid Data", 400)
}
Sending only res.status(400) without .send will only return a 200 res. Everything works fine but an error is thrown: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client. This happens only because I send a message after the status code res.status(400).send("Invalid Data"), but as I said, returning only a status code res.status(400) will not affect the response status leaving it to 200. What should I do?
It's also possible that
throw new ServerError("Invalid Data", 400)
is causing the problem. A synchronous exception in a request handler will be caught by express and it will attempt to send an error response, but you've already done
res.status(400).send(...)
So, remove either the throw new ServerError("Invalid Data", 400) or the res.status(400).send("Invalid Data"). Don't have both. That's a guess, we need to see the WHOLE request handler to know for sure what to suggest. And, depending upon how the code is structured, you may also need a return to keep any other code paths from executing.
module.exports = function protectedRoute(request, response, next) {
const token = request.headers.authorization;
if (!token) {
return response.status(401).json({ message: 'invalid or token missing' });
}
const accessToken = token.split(' ')[1];
jwt.verify(accessToken, 'access', (error, user) => {
if (error) {
response.status(401).json({ message: 'User not authenticated' });
} else {
request.user = user;
next();
}
});
};
Eslint is giving an error: "Expected to return value at the end of function". Now I solved this using:
return null; // at the end of the function
But I want to return something meaningful like:
return response.status(503).json({ message: 'service unavailable' });
But this return gives error on API call: "Cannot set headers after they are sent to the client"
Any suggestions on how to deal with this?
The return value of a middleware function like this never examined, therefore it need not return anything. To satisfy eslint, return null; is fine.
The problem with your "meaningful" return statement is that it synchronously sends a response to the client independent of the outcome of the jwt.verify statement. This outcome is handled asychronously, in the (error, user) => ... callback function. So what happens is: First the 503 response is sent with the "service unavailable" message, and then
either a 401 response is sent with "user not authenticated" (if the callback has an error)
or the next middleware is invoked and will try to send a response.
In both cases, the headers of the second response are set after the first response has already been sent, hence the error. Sending two responses does not make sense, of course.
i am using request package and it works but after performing request and sending status code to user it continues to execute code even though i use return. here is my code
request(longurl, {method: 'HEAD'}, function(error,response,body){
if(error){
return res.status(409).send({
message: 'URL is not valid'
})
}
})
if(other_condition){
return res.status(409).send({})
}
and it gives me
(node:3040) UnhandledPromiseRejectionWarning: Error: Can't set headers
after they are sent.
The problem is that you are calling return in a callback function. This is making that function return, but the outer function will continue execution. Perhaps your other_condition check should be inside the callback, and then you won't need the return statements.
request(longurl, {method: 'HEAD'}, function(error,response,body){
if(error){
res.status(409).send({
message: 'URL is not valid'
})
} else if(other_condition){
res.status(409).send({})
}
})
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
I have a form in my react which allows users fill out their info and then sends a Post requests to create a new user in my database once submitted. I am using axios to make the http call with a node backend. The post request works on the backend, but I am now trying to handle errors on the front end (i.e. if a user enters an invalid email, the backend catches this and sends an error status back, and I want to display a message to the user saying they need to enter a valid email, etc).
I have the following code on my backend to handle the request:
const { check, validationResult } = require('express-validator/check');
studentRoutes.route('/add').post([
check('email').isEmail(), check('class_year').isInt({min: 2014, max: 2022})],
function (req, res) {
//make sure input is valid
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
.
.
.
//post call succesful
res.status(200).send("Student successfully Added to database");
});
On the front end, I make the http call as follows:
app.post('student/add', obj)
.then(res => console.log(res.data))
.catch(err => console.log(err));
where app is axios.
When I try this with correct data (i.e. should not return error), the message "Student successfully added to database" prints to the console as expected.
When I try this with a bad email (i.e. should return error), all that is printed to my console is:
(X) POST http://localhost:4000/student/add 422 (Unprocessable Entity)
Error: Request failed with status code 422
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
Where the first POST error is caught by my browser and the second part starting "Error: ..." is printed to the console.
When I try to access the error (err.errors or similar) it returns undefined. How can I access the status code and the body of the error sent?
Note: I have also tried replacing the line return res.status(422).json({ errors: errors.array() }); with return res.status(422).send({ errors: errors.array() }); but that does not help and the results are the same.
You should be able to access like this:
catch (err) {
console.error(err.response.data.errors);
}
Try:
error.message
Or depending on the backend config:
error.response