KAHIBARO
Discord Login Register

7.13. HTTP Status Codes

Understanding HTTP Status Codes

HTTP status codes are short numeric codes that tell the client what happened with its request. Every HTTP response has a status line, which includes:

Example raw response start:

http
HTTP/1.1 200 OK
Content-Type: application/json

As a backend developer, returning the correct status code is critical. It affects:

In this chapter we will focus on how to use status codes correctly in REST APIs, not the full protocol theory behind them.

Important rule:
Always return a status code that matches what actually happened on the server.
Never use 200 OK for everything.


Status Code Categories

All status codes are 3 digits. The first digit describes the category:

RangeCategoryTypical Meaning
1xxInformationalRequest received, processing continues
2xxSuccessRequest was successfully received and handled
3xxRedirectionClient must take additional action
4xxClient errorProblem with the request
5xxServer errorServer failed to process a valid request

For REST APIs, you will mostly use:

Common 2xx Success Codes

2xx codes mean "the request was successfully received, understood, and accepted."

200 OK

Use when the request succeeded and you return a response body.

Typical cases:

Example: GET a list of users

http
GET /users HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
[
  {"id": 1, "name": "Alice"},
  {"id": 2, "name": "Bob"}
]

201 Created

Use when a new resource has been created as a result of the request, usually with POST.

You should also include a Location header with the URL of the new resource.

Example: Create a new user

http
POST /users HTTP/1.1
Content-Type: application/json
{"name": "Alice"}
HTTP/1.1 201 Created
Location: /users/1
Content-Type: application/json
{"id": 1, "name": "Alice"}

In REST APIs, 201 Created is preferred over 200 OK for successful creation.

202 Accepted

Use when the request has been accepted for processing, but the processing is not complete yet.

Typical for:

Example: Start a report generation job

http
POST /reports HTTP/1.1
Content-Type: application/json
{"type": "monthly"}
HTTP/1.1 202 Accepted
Content-Type: application/json
{"job_id": "abc123", "status": "pending"}

The actual report will be generated later. The client might poll another endpoint to check status.

204 No Content

Use when the request succeeded but there is no response body.

Typical cases:

Example: Delete a user

http
DELETE /users/1 HTTP/1.1
HTTP/1.1 204 No Content

Do not include a response body with 204. Many HTTP clients will ignore it.


Common 3xx Redirection Codes

In pure APIs, 3xx codes are less common but still important.

301 Moved Permanently

Use when a resource has permanently moved to a new URL. Helpful when you reorganize your API.

Example:

http
GET /v1/users HTTP/1.1
HTTP/1.1 301 Moved Permanently
Location: /v2/users

Clients should update their URLs.

302 Found

Traditional web redirect, often used after form submissions in browser apps.

In pure JSON APIs, you usually avoid 302, and instead return 200/201 with JSON that tells the client what to do.

304 Not Modified

Used with caching. Means the resource has not changed since the last request, so the client can use its cached version.

Example flow:

  1. Client sends If-None-Match header with an ETag
  2. Server responds with 304 if nothing changed
http
GET /users/1 HTTP/1.1
If-None-Match: "v1"
HTTP/1.1 304 Not Modified

No response body is sent.


Common 4xx Client Error Codes

4xx codes mean "the client did something wrong" or "the client must change something."

400 Bad Request

Use when the request is malformed or invalid, and no more specific 4xx code fits.

Typical cases:

Example: Invalid JSON

http
POST /users HTTP/1.1
Content-Type: application/json
{"name": "Alice"   // missing closing brace
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
  "error": "invalid_request",
  "message": "Body contains invalid JSON"
}

401 Unauthorized

Despite the name, 401 actually means "unauthenticated." Use when the request has no valid authentication credentials.

Typical cases:

Example: Missing token

http
GET /me HTTP/1.1
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
Content-Type: application/json
{
  "error": "unauthorized",
  "message": "Authentication credentials were not provided"
}

403 Forbidden

Use when the user is authenticated, but does not have permission to perform the action.

Comparison:

CodeMeaningExample
401Not authenticatedNot logged in
403Authenticated, but not allowedLogged in as user, trying to access admin page

Example: Normal user trying to access admin data

http
GET /admin/users HTTP/1.1
Authorization: Bearer user-token
HTTP/1.1 403 Forbidden
Content-Type: application/json
{
  "error": "forbidden",
  "message": "You do not have permission to access this resource"
}

404 Not Found

Use when a resource cannot be found, or you do not want to reveal it exists.

Typical cases:

Example: User does not exist

http
GET /users/9999 HTTP/1.1
HTTP/1.1 404 Not Found
Content-Type: application/json
{
  "error": "not_found",
  "message": "User not found"
}

Security example: Hiding whether an email exists in the system:

http
POST /password-reset HTTP/1.1
Content-Type: application/json
{"email": "unknown@example.com"}
HTTP/1.1 200 OK
Content-Type: application/json
{"message": "If an account with this email exists, a reset link has been sent"}

You might still log internally that the email was not found, but you do not reveal it to the client.

405 Method Not Allowed

Use when the HTTP method is not allowed for the requested resource.

Example: You support GET on /users/1, but not POST.

http
POST /users/1 HTTP/1.1
HTTP/1.1 405 Method Not Allowed
Allow: GET, PUT, DELETE
Content-Type: application/json
{
  "error": "method_not_allowed",
  "message": "Method POST is not allowed for this resource"
}

409 Conflict

Use when the request conflicts with the current state of the resource.

Typical cases:

Example: Username already taken

http
POST /users HTTP/1.1
Content-Type: application/json
{"username": "alice"}
HTTP/1.1 409 Conflict
Content-Type: application/json
{
  "error": "conflict",
  "message": "Username already exists"
}

410 Gone

Use when a resource used to exist, but has been permanently removed and will not return.

Less common, but useful when you want to explicitly say a resource is gone, not just unknown.

415 Unsupported Media Type

Use when the server cannot handle the format of the body.

Example: API expects JSON, but client sends XML.

http
POST /users HTTP/1.1
Content-Type: application/xml
<user><name>Alice</name></user>
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
{
  "error": "unsupported_media_type",
  "message": "Content type application/xml is not supported. Use application/json"
}

422 Unprocessable Entity

Common in modern APIs for semantic validation errors. The request body is well-formed, but the data is invalid.

Typical cases:

Many frameworks, such as FastAPI, use 422 by default for validation errors.

Example: Invalid data

http
POST /users HTTP/1.1
Content-Type: application/json
{"email": "not-an-email", "age": 10}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
  "error": "validation_error",
  "details": [
    {"field": "email", "message": "Invalid email address"},
    {"field": "age", "message": "Must be at least 13"}
  ]
}

429 Too Many Requests

Use when a client has sent too many requests in a given period, for rate limiting.

Example:

http
GET /search?q=test HTTP/1.1
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
  "error": "too_many_requests",
  "message": "Rate limit exceeded. Try again in 60 seconds"
}

The Retry-After header tells the client when to try again.


Common 5xx Server Error Codes

5xx codes mean something went wrong on the server side.

Important rule:
Use 5xx codes only when the server is at fault, not the client.
If the client sent a bad request, use a 4xx code, even if your code crashed while handling it.

500 Internal Server Error

Generic server error when something unexpected happens and no specific 5xx code applies.

Typical cases:

Example:

http
GET /users HTTP/1.1
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
  "error": "internal_server_error",
  "message": "An unexpected error occurred"
}

In production, do not return stack traces or sensitive details to the client. Log them on the server instead.

502 Bad Gateway

Use when your server is a gateway or proxy and receives an invalid response from an upstream server.

Example scenarios:

In many setups, the reverse proxy (like Nginx) or load balancer will return 502, not your application code.

503 Service Unavailable

Use when the service is temporarily unavailable, for example:

You can include a Retry-After header to tell clients how long to wait.

Example:

http
GET /users HTTP/1.1
HTTP/1.1 503 Service Unavailable
Retry-After: 120
Content-Type: application/json
{
  "error": "service_unavailable",
  "message": "Service is temporarily down for maintenance"
}

504 Gateway Timeout

Use when acting as a gateway or proxy and an upstream server takes too long to respond.

Example:

Again, often returned by infrastructure rather than your own application code.


Choosing the Right Status Code in REST APIs

You will often need to decide which code to use. Here are common REST actions and typical codes.

Typical Status Codes by HTTP Method

OperationMethodTypical Status Codes
Get a list of resourcesGET200
Get a single resourceGET200, 404
Create a new resourcePOST201, 400, 401, 403, 409, 422
Update a resource fullyPUT200, 204, 400, 401, 403, 404, 409, 422
Update a resource partiallyPATCH200, 204, 400, 401, 403, 404, 409, 422
Delete a resourceDELETE204, 404, 401, 403
Non-idempotent action (e.g. login)POST200, 400, 401, 422

Example: User Registration Endpoint

Requirements:

Possible responses:

http
POST /users HTTP/1.1
Content-Type: application/json
{"username": "alice", "email": "alice@example.com", "password": "short"}
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
  "error": "validation_error",
  "details": [
    {"field": "password", "message": "Password must be at least 8 characters"}
  ]
}
http
POST /users HTTP/1.1
Content-Type: application/json
{"username": "alice", "email": "alice@example.com", "password": "longpassword"}
HTTP/1.1 201 Created
Location: /users/1
Content-Type: application/json
{"id": 1, "username": "alice", "email": "alice@example.com"}
http
POST /users HTTP/1.1
Content-Type: application/json
{"username": "alice", "email": "another@example.com", "password": "longpassword"}
HTTP/1.1 409 Conflict
Content-Type: application/json
{
  "error": "conflict",
  "message": "Username already exists"
}

Example: Login Endpoint

Requirements:

http
POST /login HTTP/1.1
Content-Type: application/json
{"username": "alice", "password": "wrong"}
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
  "error": "invalid_credentials",
  "message": "Username or password is incorrect"
}
http
POST /login HTTP/1.1
Content-Type: application/json
{"username": "alice", "password": "correct-password"}
HTTP/1.1 200 OK
Content-Type: application/json
{"access_token": "jwt-token-here", "token_type": "bearer"}

Status Codes and Idempotency

Idempotent methods, such as GET, PUT, DELETE, should have consistent results if called multiple times.

Status codes help communicate this:

Example:

http
DELETE /users/1 HTTP/1.1
HTTP/1.1 204 No Content

Second attempt:

http
DELETE /users/1 HTTP/1.1
HTTP/1.1 404 Not Found
Content-Type: application/json
{"error": "not_found", "message": "User not found"}

Some APIs choose to return 204 both times for "delete if exists" semantics, but you must document this behavior clearly.


Designing Error Responses

Status codes are numeric and short. API clients also need structured error information.

A common pattern is to combine:

Example standard structure:

json
{
  "error": "validation_error",
  "message": "There were validation errors",
  "details": [
    {"field": "email", "message": "Invalid email address"}
  ]
}

Or for a simple not found:

json
{
  "error": "not_found",
  "message": "User not found"
}

Important rule:
Use HTTP status codes for the high level result,
and use JSON body fields for detailed error information.


Summary Cheat Sheet

CodePhraseTypical Use in REST APIs
200OKSuccessful GET, PUT, PATCH, POST with body
201CreatedSuccessful creation of a new resource
202AcceptedAccepted for async processing
204No ContentSuccessful delete or update without body
301Moved PermanentlyResource permanently moved
304Not ModifiedCaching, resource unchanged
400Bad RequestMalformed request, invalid syntax
401UnauthorizedAuthentication required or invalid
403ForbiddenAuthenticated but not allowed
404Not FoundResource does not exist
405Method Not AllowedMethod not supported for this endpoint
409ConflictState conflict, duplicate resource, etc.
410GoneResource permanently removed
415Unsupported Media TypeWrong Content-Type
422Unprocessable EntitySemantic validation errors
429Too Many RequestsRate limit reached
500Internal Server ErrorUnexpected server error
502Bad GatewayInvalid response from upstream
503Service UnavailableTemporary overload or maintenance
504Gateway TimeoutUpstream service timeout

As you build APIs, get into the habit of consciously choosing the status code. This small detail makes your backend more predictable, easier to integrate with, and easier to debug.

Views: 9

Comments

Please login to add a comment.

Don't have an account? Register now!