I am wondering what is the best way for me to be handling errors, and when I should be using error codes in response from my API in conjunction with an errors object.
I have just started building a multi-part form in react, every time a user moves onto the next step in the form I am sending a request to the API to validate the data before moving onto the next step, and sending back a response of true/false with an errors object if they exist.
My question is, when I am returning generic errors, e.g:
if( hasErr == true ) {
res.status(200).json({
success: false,
errors: errorsObject
});
}
Should I be sending a status of 200 back, or should I be sending back a response with an error code somewhere in the 400 range?
Currently on the client side when I am recieving a response, my basic redux action looks like this:
this.props.createlistingAction(this.state).then(
(res) => {
if( res.payload.success == true ) {
console.log('Success!');
} else {
console.log('We have errors!');
this.setState({ errors: res.payload.errors });
}
console.log(res);
//this.props.history.push('/'),
},
(err) => { // error
console.log(err.response);
this.setState({errors: err.response.data.errors, isLoading: false});
}
);
Is it ok to be handling errors like this? Or if you do suggest I send back a 400 error response, how should I be getting these errors when the payload only contains a generic error "Error: Request failed with status code 400 at createError"?
Thanks
You can also return a content with a status code different by 200.
So you should easily return the HTTP Status Code related to the error and the error details in the body of your response.
Related
I am new to angular 10 and I am trying to make an http post to a PHP file as shown below
this.http.post(`${environment.server}/path/file.php`, {param1, param2})
.subscribe(
data => {
console.log(JSON.stringify(data));
},
error => {
console.log(error);
this.error = error;
});
The file is successfully called and returns the following JSON as displayed in the console response
{"Email":null,"school_year":2021,"academic_year":"2021"}
When I make the request I am immediately taken to the error state and all the console log is showing below only prints "OK"
console.log(error);
The two questions are the following
Why am getting to the error when the file is successfully returning JSON
Is there a way to get a more helpful error message than just OK
You will need to set the content type to application/json
You would be better off if you used a rest API rather than using php files. .NET Core or Node.JS would give you a better development experience.
It seems that your back-end PHP send the response with status code 400. It should be revised to 200 to get the data in response. When Status code is in Error range like 400, 401, 403 ... http Response will resolved in error or catch part.
In addition if you want just get data, it's better to use GET instead of POST.
I have a react component and I'm making a network call to set the state. Eventually I want to pass this down to other child components, but just getting the plumbing to work at the moment.
I'm trying to catch errors correctly when calling out to my backend (an express server in the app). I attempted to force an error by fetching data from an endpoint that doesn't exist. This should throw a 404 since it doesn't exist, right? How can I get that error surfaced in the catch statement? Right now my error is SyntaxError: Unexpected token < in JSON at position 0 at eval (app.js:61)
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
fetch('/api/wrong_endpoint').then((data) => {
return data.json();
}).then((body) => {
this.setState({data: body})
}).catch(err => console.log(err));
}
render() {
console.log('logging the states');
console.log(this.state.data);
return (
<div>
<ContactList />
<ContactDetail />
<AddContactModal />
</div>
);
}
}
I'll try to go step by step
fetch method doesn't throw an error even if you get the 4xx or 5xx response codes. Please read about the Fetch API carefully, I believe you can find a lot of interesting you don't know about it.
You can easily check the response status as follows (please read about the Response object and its methods/properties):
fetch('/api/wrong_endpoint').then((response) => {
console.log('status code', response.status)
})
It's hard to say if your server really returns 404 code because I don't know your express setup. If you set some fallback handler like app.get('*', ...) then it might as well return 200 success code. You can check the response status and its body in devTools of the browser. But I believe it's better if you configure at least your /api router to return 404 error if the requested /api/... route isn't found.
What I'm really sure of is that your server returns some HTML layout in the response. And you try to parse it as JSON string via data.json() and of course you get the syntax error since it's not JSON (html layout starts with < symbol hence the error: SyntaxError: Unexpected token <)
Generally, if you are using the fetch API, errors 40x and 50x will not go into the subsequent blocks, as the promise from fetch only rejects network errors (not HTTP errors or anything else). Therefore, requesting for data from an 'incorrect' endpoint will be handled within the first then block.
I would recommend you to use check your http response body based on the Response.Ok property. Successful responses will be handled within that condition, whereas any other responses (ok: false) will be handled on the other statement.
fetch('/api/wrong_endpoint')
.then(response => {
console.log(response) // full response body
console.log(response.status); // get only the response.status
if (!response.ok) {
// http errors 40x and 50x will go into this statement
// do something to handle it
} else if (response.ok) {
// handles status code 200
}
})
.then(
// ...
I have been stuck deciding which method is the best practice for error handling. This involves sending requests from Axios client side, to Laravel server side. I've got two different methods for how I could potentially handle errors. Which would be best practice and why?
For this example we will use fetching profile information from the server in JSON format.
First method for error handling:
Server side would look like this, it returns two different JSON responses dependent on whether it's a success or error. Firstly a successful response, and then an error response.
//success response
return response()->json([
'success' => true,
'data' => []
], 200);
//error response
return response()->json([
'success' => false,
'error' => []
], 400);
Client side would look like this, this sends a request through Axios to fetch profile information and handles it accordingly to the HTTP response.
axios.get('/json/profile')
.then((response) => {
// handle success response (HTTP CODE 200)
})
.catch((error) => {
// handle error response (HTTP CODE 400)
});
The issue with this method is that in the console you'll get messages like this:
The second method for error handling:
This method avoids having messages like that in the console by always returning a HTTP response code of 200, with an error message if it's a failure.
The server side would look like this, the only thing that changes is the "success" value in the JSON server response.
//success response
return response()->json([
'success' => true,
'data' => []
], 200);
//error response
return response()->json([
'success' => false,
'error' => []
], 200);
The client side would look like this, it'll check the success part of the response whether it's true or false to determine whether it's an error or not.
axios.get('/json/profile')
.then((response) => {
if (response.success) {
//handle success
} else {
//handle error
}
});
Using the second method avoids any error information been passed into the users console.
This problem annoys me, because I know it has something to do with me not understanding the issue properly - which makes it really hard to track down answers for, despite spending hours reading and trying different things.
My question/problem is this, I am saving a user to a mongodb database when they signup, my schema doesn't allow for duplicate emails, and sends me back an error. I am able to console log the error in the terminal, but I am having problems sending it back to the client. Or I'm having a problem doing something with it, if it comes back, I'm not too sure where in those two steps I am losing access to the error message.
Here is my POST route for saving the user:
router.post('/users', (req, res) => {
let body = _.pick(req.body, ['email', 'password']);
let user = new User(body);
user.save().then(() => { // this all works and will save the user, if there are no errors
return user.generateAuthToken();
}).then((token) => {
res.header('Authorization', `Bearer ${token}`).send(user);
}).catch((err) => { // This is where my problem is
console.log(err); // This will log the mongodb error here, about duplicate emails
res.status(500).send(err); // I'm trying to send the mongodb error message back to the client to display it on the screen (I will handle making the message friendly to read, once I can get this to work)
});
});
So my catch is getting the mongo error, and then I try to respond with it, by sending it to the client.
Here is my client side code:
axios({
method: 'post',
url: '/auth/users',
headers: {
'Content-Type': 'application/json'
},
data: {
email,
password
}
}).then((res) => {
console.log('this is the response', res);
if (res.status === 200) {
var authToken = res.headers.authorization.split(' ')[1];
authenticateUser(authToken);
this.props.history.replace('/dashboard');
} // This all works fine for a signup with no errors
}).catch((err) => {
console.log('Signup error:', err);
// I am expecting the above line of code to log the long Mongodb
// error message that I am sending back in my res.status(500).send(err)
// catch call from the server, but instead all I am getting is
// "Signup error: Error: Request failed with status code 500"
});
Either I'm not sending the error correctly, or I'm not handling it correctly when it comes back, but I have no idea which it is or why.
I can't even send back res.status(500).send('some string here') and access that string.
Thanks
Update
So I just checked in postman, by sending a POST that could cause the error, and I am getting the correct response sent through.
My server catch actually looks like this:
.catch((err) => {
res.status(500).send({message: err.message});
});
And the postman response body looks like this:
{
"message": "E11000 duplicate key error collection: authBoilerplate.users index: email_1 dup key: { : \"email#example.com\" }"
}
So I'm just not handling it correctly in my client side code, still at a loss though.
Thanks everyone, I was able to find the answer to my question, so I'm posting it here in the hope that it might help someone else.
I was definitely sending my custom error message back, I just wasn't handling it properly on the client side.
When I was using a catch call on the client and logging the error, I was expecting to see everything included in the error. It turns out that the error comes back with a response property error.response, and that is where all the messaging is.
So changing my catch call to this:
axios(//... send post in here)
.then(// ... same as in my question)
.catch((err) => {
console.log('error', err);
console.log('error response', err.response); // this is where the actual error response message is error.response.message
});
resulted in logging the stack trace and the error response:
error Error: Request failed with status code 500
at createError (eval at <anonymous> (bundle.js:541), <anonymous>:16:15)
at settle (eval at <anonymous> (bundle.js:847), <anonymous>:18:12)
at XMLHttpRequest.handleLoad (eval at <anonymous> (bundle.js:520), <anonymous>:77:7)
error response Object {data: Object, status: 500, statusText: "Internal Server Error", headers: Object, config: Object…}
I was still expecting to be able to see that I had access to that 'response' property by logging just the error, so if anyone has any insight into that, it would be great to include in the comments.
Another way of solving this is by converting the error to string.
.catch((err) => {
res.status(500).send(err.toString());
});
Consider following code. It's just a simple http post request with axios library.
axios.post('http://localhost/users', this.state)
.then(function(response) {
if (response.status == 201) {
browserHistory.push('/features');
}
})
.catch(function(error) {
console.log(error);
})
If user enters a wrong data to an input, the response from server holds info, e.g.
password has to be longer then...
mail missing the # sign
etc...
but unfortunately, I don't know how to get into that response if there's a 400 bad request status. It just shows the error, but I'm unable to get the response.
If the response status is 201, it properly shows the response. But in case of 400, even if I change the condition and add else if (response.status == 400) { console.log(response) } it doesn't show up the response.
Any help highly appreciated.
Just looking at the axios documentation, it looks like the response should be exposed in the error object (i.e. console.log(error.response)).
More information about different info provided when the response code falls out of 2xx here: https://github.com/mzabriskie/axios#handling-errors
you need to log the data of the response:
axios.post('http://localhost/users', this.state)
.then(function(response) {
browserHistory.push('/features');
})
.catch(function(error) {
console.log(error.response.data); // this is the part you need that catches 400 request
});