How to fetch response body using fetch in case of HTTP error 422? How to fetch response body using fetch in case of HTTP error 422? reactjs reactjs

How to fetch response body using fetch in case of HTTP error 422?


Short answer

Because your assumption that you parse the response content twice is incorrect. In the original snippet, the then after the then(checkStatus) is skipped when the error condition is met.

Long answer

In general, well-structured promise chain consists of a:

  1. Promise to be fulfilled or rejected sometime in the future
  2. then handler that is run only upon fulfillment of the Promise
  3. catch handler that is run only upon rejection of the Promise
  4. finally (optional) that is run when a Promise is settled (in either 2 or 3)

Each of the handlers in 2 and 3 return a Promise to enable chaining.

Next, fetch method of the Fetch API rejects only on network failures, so the first then method is called regardless of the status code of the response. Your first handler, the onFulfilled callback returns either a fulfilled or rejected Promise.

If fulfilled, it passes control to the next then method call in the chain, where you extract JSON by calling json method on the response, which is then passed as Promise value to the last then method to be used in the successCallback.

If rejected, the control is passed to the catch method call, which receives the Promise with the value set to new Error(response) that you then promptly pass to errorCallback. Therefore, the latter receives an instance of Error, whose value is an instance of Response from Fetch API.

That is exactly what you see logged: Error: [object Response], a result of calling toString method on an instance of Error. The first part is the constructor name, and the second is a string tag of the contents (of the form [type Constructor]).

What to do?

Since your API returns JSON response for every possible use case (201, 404, 422), pass the parsed response to both fulfilled and rejected promise. Also, note that you accidentally declared checkStatus on the global scope by omitting a var, const, or let keyword:

//mock Response objectconst res = {  status: 200,  body: "mock",  async json() {    const {      body    } = this;    return body;  }};const checkStatus = async (response) => {  const parsed = await response.json();  const {    status  } = response;  if (status >= 200 && status < 300) {    return parsed;  }  return Promise.reject(new Error(parsed));};const test = () => {  return checkStatus(res)    .then(console.log)    .catch((err) => console.warn(err.message))    .finally(() => {      if (res.status === 200) {        res.status = 422;        return test();      }    });};test();