I think that it should be irrelevant how many status codes are used, so long as they are documented and used consistently.
I’ve spent the last few months working with an API that sometimes returns a 4xx or 5xx and other times a 200 with a verbose error in JSON for the same error, completely defeating the purpose of status codes.
Because they’ve been unwilling to embrace the existing http status codes they’ve effectively coded another set of status codes in JSON in addition to the existing ones.
I used to be careful about returning specific HTTP codes, 404 for resource not found, 401 not authorized, etc. but I found out that there’s no point in doing so.
As far as the client is concerned, the logic is usually “if 200 - great, else show error message”. Almost no client is going to carefully check what the HTTP code is and do something special for it.
It’s much better to return clear, verbose error messages (or well documented error codes) so that whoever is working with the API knows exactly what the problem is, when there is a problem. So for me it’s just either 200 (OK) or 400 (error).
And those that do want to do something specific generally need an application-specific error code with more detail than HTTP could provide.
I do think it’s worth distinguishing between client failure and server failure though, they require different handling (client should retry server errors but not client errors). So I’d say it’s 2xx (OK), 4xx (You messed up your request), or 5xx (I messed up my processing).
RFC 7231 lets us extend status codes. I try to do this when possible for application-specific responses. So 451 may mean you sent foo, bar but forgot baz and that’s not allowed. And 550 might signal that downstream services aren’t reachable so the service you are calling is dead.
I like doing this because it seems to make error handling a bit easier: I don’t have to worry about different serializations for errors depending on which content you negotiated, and I can leave handling the error up to the client - maybe you can address 451, but you can’t address 452-455, so you handle 451 and let 452-455 = 4xx.
I’ve also had better luck with putting these things behind proxies and load balancers. I’d hate to go with the Facebook-style “200 everything!” in those cases.
I do think it’s worth distinguishing between client failure and server failure though
Agreed! If you do nothing else, do this!
I once called out a programmer whose code amounted to “if 200; ok; else if 404; bad”. He insisted that was sufficient because the web service he called could never return anything but a 404 or a 200!
pkill unicorn on dev gave him valuable insight into the ops-side of his code.
This was the approached I picked up from someone when designing our APIs back in they day and it stuck around. Generally I have an accompanying error code for my 400s to specify what exactly went wrong: either the input couldn’t be parsed, or something about the input was invalid, or some business rule-based constraints about the input were not met and hence the 400. A simple string error code for these conditions seems to suffice given that most non-public APIs don’t need to be fancy about error reporting, just good enough to keep developers sane at development time.
[Comment removed by author]
There’s no need to be this abusive. It is perfectly possible to criticize shortcomings (even severe ones) calmly, politely, and with respect for the human beings on the receiving end.
What and why do you disagree with in the article?