Artur Kasperek
Artur Kasperek

Reputation: 645

How to handle HTTP code 4xx responses in fetch api

I was wondering how we should handle 400 from backend when we use ajax function. We can make if statement in promise resolve function and check if res status is 400. Different approach is making wrapper service for fetch, and when we got 400 from server we throw exception. How to deal with that problem ?

Upvotes: 28

Views: 43751

Answers (4)

Jack Ryan
Jack Ryan

Reputation: 1318

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)

Upvotes: 1

jfriend00
jfriend00

Reputation: 707876

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
    })
}

Upvotes: 33

IsmailS
IsmailS

Reputation: 10863

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

Upvotes: 8

Madara's Ghost
Madara's Ghost

Reputation: 175038

Incorporating it into your HTTP abstraction is probably a good idea. Perhaps with some sort of options argument:

const myFetch = (method, path, {headers, strictErrors, whatever}) => {
  // fetch here, if strictErrors is true, reject on error.
  // return a Promise.
}

myFetch('GET', 'somepath', {strictErrors: true})
  .then(response => {})
  .catch(err => { /* maybe 400 */ });

A wrapper around fetch is generally a good idea, fetch is a relatively low level function. Just as it isn't a good idea to directly create new XHR objects everywhere, I believe it isn't a good idea to directly call fetch() in various parts of your application. It's akin to a global variable, in some ways.

Upvotes: 1

Related Questions