DEV Community

Cover image for You're Not Using HTTP Status Codes Right

You're Not Using HTTP Status Codes Right

Pragati Verma on August 21, 2022

HTTP status codes are like short messages returned from a server whenever we request or interact with a resource on the server. They are an invalua...
Collapse
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard

I use HTTP 200 everywhere because Facebook says it's the best practice now #graphql

Collapse
 
luiz0x29a profile image
Real AI

eeew

Collapse
 
dendihandian profile image
Dendi Handian

Source please?

Collapse
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard • Edited

If you are doing REST, you can ignore my snarky comment and read the fine article instead.

For GraphQL specifically, Facebook took the somewhat controversial decision to throw away all HTTP codes and verbs and server-side caching mechanisms. Everything is a POST { "query": "graphql query", variables: { json } } to example.com/graphql and returns HTTP 200 OK. Exceptions and failures are treated via another mechanism. Caching... who needs caching?

See for example 200 OK! Error Handling in GraphQL and serving GraphQL over HTTP

Thread Thread
 
pragativerma18 profile image
Pragati Verma

Thanks for sharing this @jmfayard, I have only worked with REST APIs, so this is mostly about it, but I am glad that now the readers can understand the context for GraphQL from your comment as well.

Thread Thread
 
joelbonetr profile image
JoelBonetR πŸ₯‡

@jmfayard isn't a world without errors the one we want? πŸ˜‚
At the end is a design decision and you can use it or not. Apollo sure has some errors available. Got your point anyway 😁

Thread Thread
 
jmfayard profile image
Jean-Michel πŸ•΅πŸ»β€β™‚οΈ Fayard • Edited

I think the way graphql handle errors is surprising at first but fine in the end.
On the other hand the decision to just disregard the built-in HTTP server side caching is IMHO very questionable.
Depending on your use case, that may be a reason to prefer to stick to REST.

Thread Thread
 
joelbonetr profile image
JoelBonetR πŸ₯‡
On the other hand the decision to just disregard the built-in HTTP server side caching is IMHO very questionable.

In an endpoint-based API, clients can use HTTP caching to easily avoid refetching resources, and for identifying when two resources are the same.
The URL in these APIs is a globally unique identifier that the client can leverage to build a cache.
In GraphQL, though, there's no URL-like primitive that provides this globally unique identifier for a given object. It's hence a best practice for the API to expose such an identifier for clients to use.
source

You can extend that to specific fields easily instead caching the whole response, see example

Collapse
 
incrementis profile image
Akin C.

Hello Pragati Verma,

thank you for your article.
It's easy to read and the examples you give are easy to understand.

Collapse
 
pragativerma18 profile image
Pragati Verma

Thank you. I am glad that you liked it :D

Collapse
 
devgancode profile image
Ganesh Patil

Great share! πŸ’―
@pragativerma18

Collapse
 
pragativerma18 profile image
Pragati Verma

Thank you. I am glad that you liked it 😁

Collapse
 
boanjfm profile image
Bo Andersen

Assuming that /users is the resource used even when doing a GET /users?name=sam, and obtaining a 404 HTTP status code makes no sense because the resource /users exists

Some people argue that query is part of the resource: en.wikipedia.org/wiki/URL

Collapse
 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

Plus using /users?name=sam you're seeking for a given resource (a user who's name is sam) and if there is none, then the resource could not be found, hence the 404 - Not Found.

On the other hand, if you request for /users I totally agree on receiving an empty array as response.

Collapse
 
ccoveille profile image
Christophe Colombier

Your article is good.

It shows a way to consider http code.

Unfortunately, it's very complicated 😁

Mostly because it depends on what you do, and who uses your API.

When working on an REST server, I would say that everything you said is OK.

But, you could also consider that http code were not designed for this. So any implementation could be ok.

I would say that http codes are simply things of an other era from the beginning of internet.

When using a rest server, the only thing that matters is the error codes you returns.

So for my point of view, as long as you define a pattern such as:

  • the end point doesn't exist: 404
  • the server cannot handle what you sent, because you send an XML and the server handles Jason only. => 400
  • everything else could be a 200
    • you are creating/updating/deleting a resource (when you talked about using 204), return a simple "ok:true" or "acknowledged:true"
    • the password cannot be accepted => 200 + error code about password that cannot be accepted
    • you search something that do not exist => 200

Someone is consuming your API, the way some libraries are working lead to problems when the server returns something else than a 2XX. I'm thinking about JavaScript here. You can count on developers to handle the success, but not the errors. It will lead to JavaScript app that will stale because they didn't handle the fact that you may return the fact the password can be unaccepted.

Also please consider that Google Chrome or Firefox will report non 2xx as errors. Some of your clients may report you this as a problem because they appear in red in the console.

People will have to handle the errors you return. I18n matters.

Http codes won't be enough, so I would say the only thing that matters is the error code you return.

Collapse
 
jnv profile image
Jan Vlnas

Someone is consuming your API, the way some libraries are working lead to problems when the server returns something else than a 2XX. I'm thinking about JavaScript here. You can count on developers to handle the success, but not the errors. It will lead to JavaScript app that will stale because they didn't handle the fact that you may return the fact the password can be unaccepted.

I can claim the opposite: a poorly written library won't handle the response correctly and will just look at the response status code. Have fun debugging that. The response claims everything is okay, the error won't pop out on you in HTTP logs, and the client library may end up passing garbage data to your application (think of all the times dealing with "Cannot read properties of undefined" error).

In fact, JavaScript's fetch will fail only due to network error, it won't throw on 4xx or 5xx status codes. If you are opting into a wrapper library which treats different status codes as errors, maybe you should also opt into a correct error handling.

Personally, I don't see status codes as a relic of the past, but as a useful tool for handling common situations in API communication. Sure, status codes don't handle all the scenarios by themselves, but there you can use a detailed response. There's even RFC 7807 suggesting a standardized format for errors in HTTP APIs.

Anyway, no matter how you approach HTTP status codes in your API, just make sure to properly document the error responses. It will save your users a lot of pain.

Collapse
 
ccoveille profile image
Christophe Colombier

I concede. I'm not using JavaScript, I only know developers who does. And I know they faced problems few years ago because of that.

Thanks for sharing the rfc, I will read it.

Once again, http codes can be considered in multiple ways. None is invalid.

Facebook move to almost always send 200 is not stupid. It's a choice.

Http codes as error codes are only a convention between who consumes your API and you. Everything is vid as long it's documented.

I will read the rfc you mentioned, thanks for sharing

Collapse
 
joulss profile image
Joulss • Edited

Your definition of error 400 is outdated, it corresponds to the RFC 2616 (1999) which was replaced by RFC 7231 (2014) then RFC 9110 (2022) which defines error 400 as follows :

The 400 (Bad Request) status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).

Based on this definition, a 400 is perfectly acceptable in the case of a well-formed request body containing an unacceptable value. Furthermore, error 422 is basically adapted to the WebDav context (although this no longer seems to be the case in RFC 9110)

Collapse
 
stealthmusic profile image
Jan Wedel

Ohh, great article! I don’t know how many times I’ve discussed whether to use 401 or 403. it’s really helpful, to look into the specs. Especially that part that says β€žyou must not retry the request unalteredβ€œ in some cases helps to understand whether or to use one or the other.

Also, returning 404 instead of 403 make sense, this is definitely something I have learned today.

Regarding the 422, it makes sense but I have never seen any API in the wild that actually uses that. I would think that most 400 responses should actually be 422 according to the specs.

Collapse
 
luiz0x29a profile image
Real AI

500 for everything , except when its 200, effectively a bool

I'm kidding, its sarcasm.

Collapse
 
ryzorbent profile image
Thabo

Exactly what I was looking for πŸ˜ŽπŸ™πŸΎ