Reputation: 823
I just started learning ReactJS. Now I want to know how to handle response status when I make an API request using fetch. Here's my code :
componentDidMount(){
this.setState({ isLoading: true })
var id = this.props.match.params.id
const api = `bla/bla/${id}`;
console.log("start call api")
fetch(api)
.then((response) => {
if(response.status === 200){
console.log("SUCCESSS")
return response.json();
}else if(response.status === 408){
console.log("SOMETHING WENT WRONG")
this.setState({ requestFailed: true })
}
})
.then((data) => {
this.setState({ isLoading: false, downlines: data.response })
console.log("DATA STORED")
})
.catch((error) => {
this.setState({ requestFailed: true })
})
console.log("end call api")
}
I turned off my connection to make a test for 408
, but my loading is still appears.
render(){
const { isLoading, requestFailed } = this.state;
if(requestFailed){
return(
<div className="errorContainer">
<a className="errorMessage">Opss.. Something went wrong :(</a>
</div>
)
}
}
Any ideas to fix this ?
Upvotes: 27
Views: 143116
Reputation: 800
If you want to know both the json response and error code in the same return value, I recommend this method:
async function loginUser(credentials) {
var resp;
return fetch("http://127.0.0.1:8000/api/token-auth/", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(credentials)
}).then(response => {
resp = response;
return response.json();
}).then(json => {
return {
response: resp,
json: json,
error: !resp.ok
};
});
}
In this case you will get an array with response
, json
and error
field. This is a better aproach if you use API with per field error messages like this:
{"username":["This field is required."],"password":["This field is required."]}
Upvotes: 2
Reputation: 1085
If you want to capture both the response's status code and the response's body, you can use this pattern. For my projects, I've created a static class called Endpoint to handle my API calls.
export class Endpoint {
static lastStatus = '';
static Get = (url, OKCallback, errorCallback = null) => {
fetch(url)
.then(response => {
Endpoint.lastStatus = response.status;
return response.json();
})
.then(getResponse => {
if (Endpoint.lastStatus == 200) {
OKCallback(getResponse.body);
//} else if (Endpoint.lastStatus == 408) {
// Special logic or callback for status code 408 goes here.
} else {
console.log("API Error: " + JSON.stringify(getResponse));
if (errorCallback != null) {
errorCallback(getResponse);
}
}
});
}
}
If you have specific HTTP Status Codes that you want handled separately, like 408, you can add your own logic or callbacks to handle them in the second "then" block.
P.S. This way works for the cases I've tested, but I'm not sure it's the best approach. Constructive feedback is invited.
Upvotes: 0
Reputation: 2910
According to MDN documentation:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
A fetch() promise will reject with a TypeError when a network error is encountered or CORS is misconfigured on the server side, although this usually means permission issues or similar — a 404 does not constitute a network error, for example. An accurate check for a successful fetch() would include checking that the promise resolved, then checking that the Response.ok property has a value of true. The code would look something like this:
fetch('flowers.jpg').then(function(response) {
if(response.ok) {
return response.blob();
}
throw new Error('Network response was not ok.');
}).then(function(myBlob) {
var objectURL = URL.createObjectURL(myBlob);
myImage.src = objectURL;
}).catch(function(error) {
console.log('There has been a problem with your fetch operation: ',
error.message);
});
Looking at your code, I don't think your 408 error check will ever run. I don't think it did in fact. Basically what the code above is doing is returning the json response if the request is 200ish ok, otherwise it's throwing an error. If an error occurs, your second then never runs and it gets thrown to your catch block. Perhaps you can set the isLoading: false there?
Also you're log statement for end of api isn't correct. That's being called before your promise completes.
Upvotes: 12
Reputation: 371193
Throw an error when the response is not OK so that it proceeds directly to the catch
:
fetch(api)
.then((response) => {
if(!response.ok) throw new Error(response.status);
else return response.json();
})
.then((data) => {
this.setState({ isLoading: false, downlines: data.response });
console.log("DATA STORED");
})
.catch((error) => {
console.log('error: ' + error);
this.setState({ requestFailed: true });
});
Upvotes: 31