Precision in Communication: The Role of HTTP Status Codes

Precision in Communication: The Role of HTTP Status Codes
Image generated with Gemini

HTTP status codes are one of the most powerful communication tools available in an API. They provide an immediate, standardized way to convey the outcome of a request without requiring the client to inspect the payload.

Despite this, many APIs misuse or underuse status codes, reducing them to generic success or error indicators.

We all have found this kind of APIs that return 200 all the time, only to find the real result and error code baked into the response body. This is a general bad practice. You don't need to memorize all the status code, only a few will be enough for 99% of the use cases and will improve the clarity of your API contracts.

Status codes as a communication contract

Status codes are not just numeric values. They are part of the API contract. A well chosen status code allows clients to react appropriately without parsing error messages or guessing intent.

At a very high level, status codes are grouped into:

  • 2xx for successful outcomes
  • 4xx for client errors
  • 5xx for server errors

Understanding this distinction is very important. A client error indicates a problem that the client can fix and then retry the request. A server error indicates a problem the client cannot resolve.

The most important success codes

Most successful API interactions can be expressed using a small set of status codes.

200 OK indicates that the request was successful and that a representation might be included in the response.

201 Created indicates that a new resource was created. The location of the resource should be communicated via the Location header. If the client needs to display the resource, a representation can be included in the response body.

204 No Content indicates that the request was successful but no payload is returned. This is common for update or delete operations where the client already has the necessary context.

Using these codes consistently improves clarity and predictability and makes building clients to integrate with your API way easier.

Client errors and what they mean

Client error codes indicate that the request was invalid in some way.

400 Bad Request signals malformed or invalid input. The server should provide enough information for the client to correct the request and retry.

401 Unauthorized indicates missing or invalid authentication credentials, in this case the client can authenticate and retry the request.

403 Forbidden indicates that the client is authenticated but lacks permission to access the resource.

404 Not Found indicates that the requested resource does not exist or is not visible to the client.

409 Conflict is useful when a request cannot be processed due to a state conflict, such as attempting to update a stale resource.

Server errors should be explicit

Client errors can be fixed by the client, server errors are out of the client's control. We need to be very explicit on what happened and, if it's an unhandled error, log enough information to cover that case.

500 Internal Server Error is a generic fallback for unexpected or unhandled failures.

503 Service Unavailable indicates temporary unavailability, often due to maintenance or overload. When possible, the message should indicate the client they can retry the request after some time.

Server errors should be logged and monitored. Clients should not be expected to handle them beyond retrying or surfacing the error to users.

Status codes reduce ambiguity

Using precise status codes reduces the need for custom error conventions and simplifies client logic. Clients can respond differently to authentication failures, validation errors, and transient outages based solely on the status code.

Status codes are a language. When used carefully, they allow APIs to communicate clearly with minimal overhead.