DEV Community

José Pablo Ramírez Vargas
José Pablo Ramírez Vargas

Posted on

Throwing if fetch() returns response.ok === false?? Terrible!

Can anyone think of a good reason why the masses of Javascripters decided that the norm is to throw an error on non-OK HTTP responses?? Because I can't.

To me, this is a terrible practice, and everyone just seems hypnotized by it, like moths to the flame.

I hear you all, potential moths. 😄

Top comments (14)

Collapse
 
ehaynes99 profile image
Eric Haynes

Throwing AT ALL is terrible. 😄 Particularly in TS because you can't even apply types to the caught error.

At most, you should throw when the program is not working as expected. People use it for control flow, which is awful. fetch is doing the appropriate thing: it throws an error if the http transaction failed, but if you successfully made a round trip to the other side, it gives you the response. It's a disjoint union of the possible outcomes. It's up to the application to decide if a 404 is really a failure, e.g. if the user's account is mysteriously gone, but not if an image has been deleted.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

BTW, since you mention typing: What do you do to type response bodies depending on HTTP status code? I found nothing, so I had to make my own: [dr-fetch](github.com/WJSoftware/dr-fetch.

I searched for existing solutions, but only found a naive attempt: ts-fetch.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Ha, yes! You and I can be friends. 😄

Collapse
 
mistval profile image
Randall

I don't think this is a norm in the general case. But if you're expecting an okay response and you don't get one, it makes sense to throw an error. If you're expecting a non-okay response, then it doesn't make sense to throw an error.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Hello, thanks for dropping by.

Not sure I follow. Shouldn't we all expect at least one non-OK response in the majority of cases? Or maybe all cases? I mean, which API is only expected to return 200? For example, saving data typed by user is prone to errors. We should always expect 200/400 as a minimum, right? Also, if your API is microservices, you should also always expect 504 with a body that describes the reason for unavailability.

This is my line of thinking. This is why I don't understand what you say: I always should have in mind that the happy path is not the only path, right?

Also, look at ky or axios: They both throw on non-OK responses, regardless of me having in mind the possibilities. This is why I hate these packages.

Collapse
 
mistval profile image
Randall

It's often the case that a GET requests is only ever expected to respond with a 200 status.

Of course any request can return 5xx errors, but it's often not pragmatic to have your code "expect" that, in the sense of having specific handling built for it rather than using error (exception) handling. If you throw an error in that case (and the error may include the response from the service, so it can be logged, shown to the user, etc) then you can generically bubble that error (or any other) up to the user so they can can see an error message and try again later. Your logging service can pick up the error generically (including stack trace) and log it, report it to error reporting, etc, and it can get looked into (or muted, if that's the right call). With some tooling, this can be made to happen easily for any error the application throws. That's more cumbersome to achieve without using errors.

I agree with you on axios, that's actually the thing I like least about axios (though I'm aware you can change that with non-default configuration). With fetch, I can examine the status and other response characteristics, and make a conscious decision whether to treat it as an error or not.

Collapse
 
eric_b_67cb420d1a0eddc900 profile image
Eric B

I think most cases where developers expect a non-ok response, should actually be approached differently, or the API should be designed differently. Do you have an example of where people expect non-ok responses?

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Hello! The typical case is a 400 BAD REQUEST error when you POST/PUT/PATCH and the server complains about the data (data too long or out of range, etc.). Data validation is an expected scenario.

Thread Thread
 
eric_b_67cb420d1a0eddc900 profile image
Eric B

I clarified my comments as a comment to Randall. I agree that non-OK codes should be expected, but I believe they never should be wanted.

Collapse
 
mistval profile image
Randall

How about an API to get a dev.to post by slug: GET /posts/throwing-if-fetch-returns-responseok-false-terrible-4oh6 which returns 200 if successful, 404 if the post does not exist.

Thread Thread
 
eric_b_67cb420d1a0eddc900 profile image
Eric B

The 200 response is the expected response, the "happy path". There are no cases where I GET a post that I expect to not exist. If you want to check whether it exists, then you should instead have a different endpoint that returns a 200 with the value true/false for whether it exists or not.

I do think that you should handle errors, for example 404 errors, but I don't think you should specifically query an endpoint because you want to receive a 404, or some other non-ok code.

Thread Thread
 
mistval profile image
Randall

That doesn't sound completely unreasonable, but a separate "existence" endpoint would not be REST-ful and you would still have the possibility of the article existing when you call the existence endpoint, but not existing when you call the get article endpoint (even if only moments later).

I would draw a distinction between expecting a certain response and wanting a certain response. Consider a web crawler that knows about a list of dev.to articles and wants to download them all. Some of them have already been deleted, so the endpoint would return a 404 for those. The crawler wants a 200 response so it can download the article, but it should also expect and understand 404s too, and skip those articles. Anything else, it could queue to retry some number of times before giving up.

Thread Thread
 
eric_b_67cb420d1a0eddc900 profile image
Eric B

I agree with your distinction between wanting and expecting. In your original comment, I thought you meant that sometimes you want a non-OK response code. In my opinion, if you're wanting a non-OK response code, then probably you're really requesting some other information than what that endpoint is explicitly serving.

Collapse
 
eric_b_67cb420d1a0eddc900 profile image
Eric B

When you request data from an API, there is an expected response from that API. If you're fetching a User, then you expect to get a User. If you don't get a User back for whatever reason, it makes sense to handle this as an error, or at least a "not ok response" - you didn't get what you want.

Some people might just be lazy and throw an error instead of handling it, but at least then it's very clear when something goes wrong at the exact point where it goes wrong (and not at a later time because suddenly your data is an error object and not a User) and you know where to add error handling later. It could also be expected that the error is not meant to be handled there and should be propagated and handled outside of the module (like in the case of axios where you are expected to catch and handle errors). With axios, I believe you can register a global error handler too, so that any error gets handled. That's useful for websites where at the very least, any API errors can get shown to the user.

I'm not too experienced with APIs, so maybe you're right, but I wanted to provide a different view on it to help foster discussion.