REST API HTTP Status Codes
In this post, I'm sharing with you the criteria I follow about status codes when I design and develop REST APIs. If I'm missing some scenario, please contact me and I will include it.
- Consumer access to the resource successfully. e.g.
- Fetch invoice: GET /invoices/1234
- Consumer creates a new resource successfully. e.g.
- Create new invoice: POST /invoices
- Send new message to chat channel: POST /channel/1234/messages
- Backend's operation takes too much time to force the consumer to wait for. e.g.
- Request an email including a zip file with all my invoices: POST /invoices/all/downloads
- Operation involves other services in an asynchronous way (e.g. microservices sagas)
204 NO CONTENT
- Resource updated or replaced e.g. (In some cases, depending on the
use-case, it is preferable to return 200 OK with the updated resource).
- Modify an invoice: PATCH /invoices/1234
- Update invoice description: PUT /invoices/1234/description
- Resource deleted
- Delete an invoice: DELETE /invoices/1234
- Consumer needs to check if resource exists (and it does) but doesn't need the data itself. e.g.
- Check if invoice exists: HEAD /invoices/1234
- Check if user has confirmed his email: HEAD /users/92/email/confirmation
400 BAD REQUEST
- One or more request's parameters are missing.
- One or more request's parameters are unknown (in most of cases, they could be just ignored.)
- One or more request's parameters have an invalid format (e.g. invalid email format, float instead of integer, etc.)
- One or more request's parameters have an invalid value (e.g. array with too many elements, value not included in the valid values set, etc.)
- Consumer tries to sign in using bad credentials (username/password, token, etc.)
- Consumer tries to access to a protected resource without being authenticated.
- Consumer tries to access to a resource which is not allowed to for some reason: she doesn't have the appropriate role, she's not allowed to access to that specific resource, user bloking...
404 NOT FOUND
- Consumer tries to access to a non-existing resource. e.g.
- Fetch a non-existing invoice: GET /invoices/8765376
- Fetch a non-existing resource type in the system: GET /burritos
- Consumer needs to check if resource exists (and it doesn't) but doesn't need the data itself. e.g.
- Check if invoice exists: HEAD /invoices/883
- Resource was available at some time but it is not anymore. e.g.
- Access to an expired invitation to join a club: GET /clubs/123/invitations/87
- Access to a closed account: GET /accounts/28
In many cases, this can be replaced with 404 NOT FOUND or a resource's attribute, like active: false, for isntance. It does depend on the use-case. Note that "deleted" term when designing APIs is a business term; it doesn't mean that resource doesn't exist in database, but it cannot be accessed anyway from the API.
428 PRECONDITION REQUIRED
- Operation cannot be executed because resource's state is not ready yet, for any reason. e.g.
- Consumer tries to ship a product, but it needs to be confirmed in the warehouse: POST /products/1234/shipments
- User cannot buy a product because hi email has not being verified yet: POST /products/1234/purchases
500 SERVER ERROR
- Unexpected error from backend not related to any feature, domain state or a customer's request. In order to avoid any attack from hackers, when returning this error, API must not expose any information about internals whatsoever. It includes database connection errors, upstream servers errors, system resources errors (CPU, memory...) and so on.