JavaScript Fetch — Are You Handling Responses Correctly?

What many developers are not aware of.

kathimalati
3 min readJul 8, 2022
JS fetch response cover

Every JavaScript developer probably knows the fetch API. It provides an easy interface for making requests to endpoints, for fetching or posting data. However, many developers are not aware of a common mistake when using fetch.

Part of what made fetch so popular is that it returns a promise. The advantage of a promise is that it can be handled elegantly with the handler functions: then, catch, andfinally.

When the promise gets resolved, the then function will execute and if the promise gets rejected, the catch function will. Naturally, one would assume, that a successful response is handled in the then function, and an unsuccessful one, in the catch function. Surprisingly, this is not the case.

Trick question: When will a promise get resolved?

Is it whenever the HTTP response status code is 200–299?

Nope. Okay, different question. When will a promise get rejected?

Is it whenever the HTTP response status code is 400–499 or 500–599 (client or server error)?

Nope.

Let´s get to the bottom of this

If the server rejects your request with a 400–499 error, the promise is not rejected but resolved. For instance the common 401 — not authorized response code, would lead to a resolved promise.

Even if the server you are trying to fetch data from is currently facing problems and a 500 internal server error is returned, the promise will still resolve and the then handler will therefore be called. Not the catch handler.

As long as the server returns a response, ANY response, the promise will resolve. The promise will only be rejected if the server was not able to send a response to your request at all. This could happen for instance, due to a network error or if the server caught fire (dramatic I know).

What does that mean for developers using fetch

This means that you cannot only handle successful responses (response code == 2xx) in the then handler. You also have to handle unsuccessful responses there (response code != 2xx).

The easiest way to identify whether or not a response was successful, is with the Response object's ok attribute.

Response object logged to the browser console
Response object returned from the jsonplaceholder.typicode API. Screenshot from Chrome browser console.

The Response object contains the attribute ok, which is a boolean. Response.ok is true, if the response status code are in the successful (2xx) range. This is why some developers check if the status code is between 200 and 299, but checking Response.ok will actually do the exact same just shorter.

If response.ok is true, we proceed with some logic, but if it was false, the response was not successful and we need to deal with the error. A common way to do that, is to throw an error, which will cause the catch handler to be called. This way the treatment of the successful and the unsuccessful response can be separated by handler functions and the catch handler can deal with non-successful responses and rejected promises all together.

fetch("https://jsonplaceholder.typicode.com/todos")
.then(response => {
if (response.ok) {
console.log(response); // do something with successful response
}
else {
throw new Error(`HTTP error, status = ${response.status}`);
}
})
.catch(error => {
console.error(error);
})

Under the hood, this works because the then method itself also returns a promise. Throwing an error leads to that promise getting rejected, and for catch to get called. For more details on promises and error handling check out this helpful resource.

The takeaway

The important takeaway is to always check for response.ok in the then handler before executing the code that assumes a successful response. It can also be helpful to throw an error if you want to deal with an unsuccessful response further in the catch statement.

Thanks for reading! How do you handle unsuccessful responses from the fetch api? Let me know in the comments. If you learned something new, follow me on Medium for more web dev content.

Boost your frontend skills by creating an interactive resume builder with my beginner-friendly, hands-on Vue.js course.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn, YouTube, and Discord.

--

--