Why there should only be 5 HTTP response codes
I’ve developed a strong opinion about exceptions over the last few years. There are only two pieces of information that all exceptions should include:
- Whose fault is the error? Was it you, the client? Or us, the provider?
- How persistent is the error? Should you retry, and if so, should you retry in 10 seconds or 24 hours?
When the client and the provider are not on the same software team, these are the only two answers that determine how an error can be handled.
-
A client error can only be fixed by the client. For example, a field that must be an email address can only be fixed by the person editing the input.
-
Bugs like null pointer exceptions can only be fixed by the developer of the service. It’s useless the client retrying, as they will probably always hit the same code path and there’s nothing they can do about it. In this case, they need to “retry after the next deployment”.
-
Some failures, like deadlocks or other infrastructural or network errors, are transient and the client may choose to retry in a matter of seconds (for interactive uses), or minutes for a queued, batched or other background process. Webhook retries are a classic example; event delivery is often automatically retried over a period of hours and days.
Now, errors should include helpful details beyond just the answers to the questions above. For example, if the email input in a form is incorrect, the response must tell the user exactly which field is wrong and why it is wrong. But these details are pretty much always down to humans to interpret.
This leads me to the conclusion that there are only 5 necessary HTTP status codes:
200
: no error300
: no error, but client must perform a redirect*400
: client did something wrong; fix your submission before retrying500
: developer did something wrong; find a workaround or try again next week503
: temporary failure, should also provide aRetry-After
response header
*I’ll allow that the semantics of HTTP mean there probably needs to be more than 1 code for redirects. Though I reckon the differences between temporary and permanent redirects etc. could have been expressed just as well with response headers.
I’ve framed this in terms of HTTP response codes, but the same issues apply to exceptions inside your own code. When throwing an exception, ask yourself the questions: who needs to fix this, and when (if ever) should the client retry?