There are many dozen HTTP status response codes that you can return from your back-end API. Fortunately, you do not need to know and memorize every single one of them. The guide would show the essentials you need to know and how to use them correctly to write great APIs. This guide will show you how to use the essentials such as 200, 201, 400, 422, and explain why should you not be explicitly throwing 500 errors.
For front-end developers, this guide would also provide you an overview of the different HTTP response codes so you can better debug API requests.
Why is it important
It is important to use the correct status codes as they are essential to communicate statuses and errors. Using the wrong status codes can lead to end-users of an API debugging the wrong issues. It happens a lot where a back-end would throw an authorization error code when the issue has to do with the request format.
Overview
The first digit of the code helps you to quickly understand what's going on. They are essentially like this:
- 2** - Success
- 3** - Redirect
- 4** - Client-side f**ked up
- 5** - Server-side f**ked up
2** - Success
200: OK
The most standard response that was for a long time the only used code for websites. You can use this code for every success case if you wish, skipping the others here would be completely acceptable.
201: Created
These are the second most used of the 200s. It is for POST requests where new entries are created such as:
- Registering a user
- Adding a post
- Adding a directory listing
- You get the idea...
202: Accepted
This is to indicate that you have accepted a request but may not have necessarily completed it. For example, the request to the API may start to run a long processing task that you cannot confirm that it completed, like sending an OTP (one-time PIN) code.
204: No Content
No content is for APIs that return no body content, like endpoints where you would just like to check if an email is taken when users are signing up. In such cases, you could do with just success and failure status codes without needing a response body content.
3** - Redirect
Redirects are less commonly used for API purposes as APIs are often revised instead of redirected. They are more relevant for web pages.
301: Moved permanently
It indicates that the URL has been moved permanently. This can lead clients (such as a browser) to 'cache' the new URL and make them automatically call the new URL instead of trying to look up the previous URL. Since you have said it was permanent.
302: Found (aka moved temporarily)
It is the same as the 301, indicating that the client should redirect. Instead, you're declaring that it is a temporary redirect and that they should come back to looking up this URL at some point.
4** - Client error
400: Bad request
Send this when there is an error with the request such as invalid parameters, missing data, etc. It is also a generic and default code for errors that do not have any other appropriate response code.
401: Unauthorized
The code 401 has to do with authentication. It is often incorrectly interchangeably used with 403. The appropriate time to send a 401 response is to indicate that the client did not send any authentication credentials.
403: Forbidden
This error code has to do with authorization. It means they have credentials but they are wrong or insufficient. There are two common cases when a user fails authorization.
- They have sent credentials but the credentials are invalid (bad token, wrong password).
-
They have valid credentials but do not have the privilege and authorization
- A User trying to access Admin stuff
- Changing the password of an account that isn't theirs
404: Not found
The most well-known that doesn't need much explanation. For the server-side, the use case is when the client sends an unknown entity ID (which can either be in the URL or request body). For example:
- User ID not found
- Add user to a project but the project ID is not found
422: Unprocessable entity
This is often used interchangeably with 400 as a generic error code as
Unprocessable entity
can mean both I can't read it and I can read but
I can't understand it. Both these codes are generally acceptable as a generic error codes.
However, I prefer the use case where this code is for formatting errors, such as sending an XML
request body when you expect JSON and using 400 instead for generic errors.
5** - Server error
500: Internal server error
This is the code that the error handler sends when there is an unintentional error in your code. You can be very sure it is to do with a server-side coding error or config when throwing this error. The only place where you should return this is in the error handler of your back-end. Never explicitly throw this status code.
app.get('/user', (req, res) => {
if (!validate(req.body)) {
// Do not do this, intentionally send 500s
return res.status(500).send({ error: 'Error with request body validation' });
}
// ...
});
If there is an error case which you need to handle, look instead to:
- Use an appropriate 400s status code
- Throw an error and let the error handler take care of it when you are not sure how to handle it, or if you need to (edge cases)
Here is the right way to do it instead.
app.get('/user', async (req, res) => {
if (!validate(req.body)) {
// Appropriate error code
return res.status(400).send({ error: 'Error with request body validation' });
}
try {
const result = await whatCouldPossibleGoWrongHere();
} catch (e) {
// Let the error handler deal with it, sends a 500
throw new Error('I did not expect to reach here');
}
});