How to handle HTTP code 4xx responses in fetch api
This way we can handle all types of status accordingly.
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify({ user_email: email }),
}).then((response) => {
return new Promise((resolve) => response.json()
.then((json) => resolve({
status: response.status,
ok: response.ok,
json,
})));
}).then(({ status, json, ok }) => {
const message = json.message;
let color = 'black';
switch (status) {
case 400:
color = 'red';
break;
case 201:
case 200:
color = 'grey';
break;
case 500:
default:
handleUnexpected({ status, json, ok });
}
})
inspiration
I'd suggest a wrapper that checks response.ok
which will be true if the response code is 2xx.
Note this statement from the MDN page on fetch()
:
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. An HTTP status of 404 does not constitute a network error.
Here is a wrapper like this:
function fetchData() {
return fetch.apply(null, arguments).then(response => {
if (!response.ok) {
// create error object and reject if not a 2xx response code
let err = new Error("HTTP status code: " + response.status)
err.response = response
err.status = response.status
throw err
}
return response
})
}
The best approach I've found for this is to wrap it in a new Promise, and if response.ok
is false, reject the Promise with the error context.
/**
* Parses the JSON returned by a network request
*
* @param {object} response A response from a network request
*
* @return {object} The parsed JSON, status from the response
*/
function parseJSON(response) {
return new Promise((resolve) => response.json()
.then((json) => resolve({
status: response.status,
ok: response.ok,
json,
})));
}
/**
* Requests a URL, returning a promise
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
*
* @return {Promise} The request promise
*/
export default function request(url, options) {
return new Promise((resolve, reject) => {
fetch(endpoint + url, options)
.then(parseJSON)
.then((response) => {
if (response.ok) {
return resolve(response.json);
}
// extract the error from the server's json
return reject(response.json.meta.error);
})
.catch((error) => reject({
networkError: error.message,
}));
});
}
(Top comment on https://github.com/github/fetch/issues/203)