Fetch API Errors and the Principle of Least Surprise

David Barral
Dec 7, 2020 · 3 min read
Photo by pixpoetry on Unsplash

It’s possible that you still don’t know this:

The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing. (Fetch API — MDN)

I find myself explaining this during PRs and training sessions more often than not, so I thought that I might as well write it down. Newcomers and less experienced developers tend to struggle with this and there’s no reason to be ashamed.

Seeing is believing

You can test fetch easily. Create a simple express server like this one:

Point your browser to http://localhost:5000, open the DevTools console, and issue some fetch requests.

You could have expected the /error/XXX requests to reject due to the server error, but that wasn’t the case. The test code rejected cause we tried to parse as JSON the response content using res.json(). Using res.text(), the call will be resolved to the Boom! string sent by the server as the error response body:

QED. As the spec says, fetch only rejects client errors. Server errors are considered successful requests, because, from the fetch point of view, they are: the server responded with the correct headers and a body, and the connection was closed cleanly 😅.

So… is fetch broken? No, it’s not. This problem is not about what is an error and what’s not. The problem lies in the value returned by fetch: a Promise.

The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.

Completion or failure… 🤔.

POLS: The principle of least surprise

Enter the principle of least surprise (also known as the principle of least astonishment or POLA).

People are part of the system. The design should match the user’s experience, expectations, and mental models.

I think the problem lies in the API and how it clashes with developer expectations. By returning a Promise, one would normally expect it to resolve when the fetch succeeds and to reject when it fails. A server error, in any mental model is usually a failure. Thus, by only treating client errors as failures, fetch surprises developers 😌.

Some languages, like Ruby, were designed with POLS in mind, and are approachable and a joy to work with. JavaScript is not one of those languages.

What I usually do

If you’ve read some of my other stories you already know. What I usually do is decorate fetch to make my own custom fetch function that behaves exactly as I (or anyone else would expect):

  • The returned promise rejects on fetch errors and when response.ok is false.
  • It rejects using a common custom Error, that has enough information to discriminate between client and server errors if I need to.
  • As a bonus, I make one fetch method per HTTP verb, cause I find it more readable than using the method option 🤷🏽‍♀️.

Using this our tests now behave as expected 🥰.

Summary

If you didn’t know this or if you have struggled in the past handling fetch errors, don’t be ashamed. You are not alone. It has surprised many developers for many years and will continue to do so.

Trabe

We are a development studio.

Thanks to Lucas Andión

David Barral

Written by

Co-founder @Trabe. Developer drowning in a sea of pointless code.

Trabe

Trabe

We are a development studio. We use Java, Rails, and JavaScript. This is where we write about the technologies we use at Trabe.

David Barral

Written by

Co-founder @Trabe. Developer drowning in a sea of pointless code.

Trabe

Trabe

We are a development studio. We use Java, Rails, and JavaScript. This is where we write about the technologies we use at Trabe.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store