REST API 05 ๐ HTTP Status Codes (2xx, 3xx, 4xx, 5xx)
HTTP status codes are the machine-readable verdict of every API call. A client reads the first digit to decide whether to parse the body, retry the request, or surface an error to the user. A monitoring system counts 5xx responses to page an on-call engineer and ignores 4xx responses because they indicate client mistakes, not server failures. The code is not decorationโit is the contract that determines how every layer of the stack behaves before a single byte of the body is parsed .
The five families are defined by their first digit. 2xx means the request was received, understood, and accepted. 3xx means the client must take further action, usually following a Location header. 4xx means the client made a mistakeโthe request is malformed, unauthenticated, or references something that does not exist. 5xx means the server failed to fulfill a valid request . The single most important rule is never return 200 OK for a failure. A 200 wrapping {"error": "not found"} forces every client to parse bodies to detect errors, breaks caching, and hides failures from monitoring .
Key point: 2xx means success, 3xx means redirection, 4xx means client error (the client must change the request before retrying), and 5xx means server error (the request was valid, the server failed). Map every outcome to the narrowest code that describes it, never return 200 for a failure, and distinguish 401 (who are you?) from 403 (I know who you are, but you cannot do this).
Why the family matters more than the exact code
The monitoring problem. A 5xx spike pages an engineer because it means the server is broken. A 4xx spike does not, because it means clients are sending bad requests. If a server returns 200 for a validation error, the monitoring system sees success, the error rate stays at zero, and the broken endpoint goes unnoticed until a user complains. The family classification is what allows infrastructure to react correctly without understanding the application .
The retry problem. A client that receives a 5xx knows the request was valid and may retry. A client that receives a 4xx knows the request was wrong and retrying without changing it will fail again. A client that receives a 200 with an error body has no way to distinguish these cases without application-specific parsing, which defeats the purpose of a uniform interface .
The security problem. The choice between 403 and 404 can leak information. Returning 403 for a resource the user may not access confirms that the resource exists. Returning 404 uniformly hides its existence. For sensitive resources, the 404 is the safer choice . The choice between 401 and 403 has the same property: 401 means “I do not know who you are,” 403 means “I know who you are, and you are not allowed.” Returning 401 when the user is authenticated but unauthorized confuses the client and hides attacks from log analysis.
a. 2xx: success
The 2xx family means the request was successfully received, understood, and accepted . The two codes that matter most are 200 OK and 201 Created.
200 OK is the standard response for a successful GET, and for a PUT or PATCH that returns the updated resource in the body. The body contains the representation, and the client can parse it directly .
201 Created is the response for a successful POST that creates a new resource. It must include a Location header pointing to the new resource’s URI, and the body should contain the created representation .
POST /users HTTP/1.1
Content-Type: application/json
{ "name": "Alice" }
HTTP/1.1 201 Created
Location: /users/42
Content-Type: application/json
{ "id": 42, "name": "Alice" }
204 No Content is the response for a successful operation that has no body to return. It is the standard response for DELETE, and for PUT or PATCH when the server does not return the updated representation. The absence of a body is the signal: the client knows the operation succeeded because the status code says so, and there is nothing to parse .
202 Accepted is for asynchronous operations. The request was valid, but the processing is not complete. The body should contain a URL to check the status or a Retry-After header .
b. 3xx: redirection
The 3xx family means the client must take further action to complete the request, usually by following a Location header . These codes appear less often in API responses than in browser navigation, but they are not absent.
301 Moved Permanently means the resource has a new permanent URI. The client should update its bookmarks and use the new URI for future requests. 302 Found means a temporary redirect. 304 Not Modified is the caching redirect: the client’s cached copy is still valid, so the server returns only the status code and no body. The client uses its cache .
307 Temporary Redirect and 308 Permanent Redirect preserve the request method across the redirect. A POST that receives a 307 should re-send the POST to the new URI, whereas a 302 historically allowed clients to change the method to GET. For APIs, the method-preserving variants are the safer choice .
c. 4xx: client error
The 4xx family means the client made a mistake. The request is malformed, unauthenticated, or references a resource that does not exist. Retrying without changing the request will fail again .
400 Bad Request is for malformed syntax: invalid JSON, missing required fields, or a request body that does not match the expected schema. The client must fix the request before retrying .
401 Unauthorized means authentication is missing or invalid. The response should include a WWW-Authenticate header describing the authentication scheme. The client should prompt for credentials or refresh its token .
403 Forbidden means the server understood the request and the user is authenticated, but the user does not have permission to perform the action. The difference from 401 is precise: 401 is “who are you?”, 403 is “I know who you are, and you cannot do this” .
404 Not Found means the requested resource does not exist. It is the standard response for a GET on a non-existent ID, and for a DELETE on a resource that has already been removed .
405 Method Not Allowed means the URI exists but does not support the HTTP method used. The response should include an Allow header listing the supported methods .
409 Conflict means the request conflicts with the current state of the resource. A duplicate email on registration, a version mismatch on an optimistic update, or a state transition that is not allowed all produce a 409 .
422 Unprocessable Entity means the request is syntactically correct but semantically invalid. The JSON parses, the required fields are present, but a business rule is violated: an age is negative, a date range is backwards, a quantity exceeds the allowed maximum. The distinction from 400 is deliberate: 400 is “I cannot parse this,” 422 is “I parsed this and it violates a rule” .
429 Too Many Requests means the client has exceeded a rate limit. The response should include a Retry-After header telling the client when it may try again .
d. 5xx: server error
The 5xx family means the server failed to fulfill a valid request. The client did nothing wrong, and the request may succeed if retried later .
500 Internal Server Error is the generic catch-all. It means an unexpected condition prevented the server from fulfilling the request. The response body must not contain stack traces, database error messages, or internal detailsโthose belong in the server logs, not in the response .
503 Service Unavailable means the server is temporarily unable to handle the request, usually due to overload or maintenance. The response should include a Retry-After header telling the client when the service is expected to return .
Complete Example Session
The following session traces a set of API calls that produce each status code family and shows the response headers and bodies that accompany them.
// ============================================
// PART 1: 201 CREATED (POST)
// ============================================
POST /users HTTP/1.1
Content-Type: application/json
{ "name": "Alice" }
HTTP/1.1 201 Created
Location: /users/42
Content-Type: application/json
{ "id": 42, "name": "Alice" }
// The Location header points to the new resource
// The body contains the created representation
// ============================================
// PART 2: 200 OK (GET)
// ============================================
GET /users/42 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/json
{ "id": 42, "name": "Alice" }
// Standard success for retrieval
// ============================================
// PART 3: 204 NO CONTENT (DELETE)
// ============================================
DELETE /users/42 HTTP/1.1
HTTP/1.1 204 No Content
// No body; the status code is the confirmation
// ============================================
// PART 4: 404 NOT FOUND (GET on missing)
// ============================================
GET /users/99 HTTP/1.1
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "User 99 does not exist"
}
// The client knows the resource is missing without parsing an error field
// ============================================
// PART 5: 401 vs 403
// ============================================
GET /admin HTTP/1.1
// No Authorization header
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
// "Who are you?" โ authentication missing
GET /admin HTTP/1.1
Authorization: Bearer valid-token-for-alice
HTTP/1.1 403 Forbidden
// "I know you are Alice, but you are not an admin"
// ============================================
// PART 6: 400 vs 422
// ============================================
POST /users HTTP/1.1
Content-Type: application/json
{ "name": "Bob", // invalid JSON, missing closing brace
HTTP/1.1 400 Bad Request
// The server cannot parse the body
POST /users HTTP/1.1
Content-Type: application/json
{ "name": "Bob", "age": -5 }
HTTP/1.1 422 Unprocessable Entity
// The JSON parses, but age is invalid
// ============================================
// PART 7: 500 INTERNAL SERVER ERROR
// ============================================
GET /users/42 HTTP/1.1
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
{
"type": "https://api.example.com/errors/internal",
"title": "Internal Server Error",
"status": 500,
"detail": "An unexpected error occurred"
}
// No stack trace, no database details, no internal paths
The seven parts demonstrate the full lifecycle: 201 for creation with Location, 200 for retrieval, 204 for deletion with no body, 404 for a missing resource, the 401/403 distinction, the 400/422 distinction, and 500 with a sanitized error body. What the session demonstrates is that the status code is the primary signalโthe body is secondaryโand the family classification determines how the client and the infrastructure react.
Quick Reference
Status Code Families
| Family | Meaning | Client Action |
|---|---|---|
| 2xx | Success | Process the body |
| 3xx | Redirection | Follow Location |
| 4xx | Client error | Fix the request |
| 5xx | Server error | Retry or report |
Common 2xx Codes
| Code | Use |
|---|---|
200 OK | Successful GET, PUT, PATCH with body |
201 Created | Successful POST with Location |
204 No Content | Successful DELETE or update without body |
202 Accepted | Async processing queued |
Common 4xx Codes
| Code | Use |
|---|---|
400 Bad Request | Malformed syntax |
401 Unauthorized | Missing/invalid credentials |
403 Forbidden | Authenticated but not permitted |
404 Not Found | Resource does not exist |
405 Method Not Allowed | Method not supported on URI |
409 Conflict | Duplicate or state conflict |
422 Unprocessable Entity | Valid syntax, invalid semantics |
429 Too Many Requests | Rate limit exceeded |
Common 5xx Codes
| Code | Use |
|---|---|
500 Internal Server Error | Unexpected server fault |
503 Service Unavailable | Temporary overload or maintenance |
Critical Distinctions
| Pair | Distinction |
|---|---|
| 400 vs 422 | Cannot parse vs parsed but violates rule |
| 401 vs 403 | Who are you? vs I know you, you cannot |
| 403 vs 404 | Confirms existence vs hides existence |
Best Practices
โ Do This:
# Creation
POST /users โ 201 Created + Location
# Retrieval
GET /users/42 โ 200 OK + body
# Deletion
DELETE /users/42 โ 204 No Content
# Authentication failure
โ 401 Unauthorized + WWW-Authenticate
# Authorization failure
โ 403 Forbidden
โ Don’t Do This:
# 200 for a missing resource
HTTP/1.1 200 OK
{ "error": "not found" } // breaks clients and monitoring
# 500 for a client validation error
HTTP/1.1 500 Internal Server Error
{ "error": "email is required" } // should be 400 or 422
# 200 for a created resource without Location
HTTP/1.1 200 OK
{ "id": 42 } // should be 201 with Location
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| 200 for errors | Convenience | Use 4xx/5xx |
| 500 for validation | Confused about fault | Use 400 or 422 |
| 401 when authenticated | Confused 401/403 | Use 403 |
| 404 when forbidden | Hiding existence is optional | Use 404 uniformly for sensitive resources |
| Stack trace in 500 | Debugging leftover | Sanitize the body |
Real-World Examples
1. Create success
POST /users โ 201 Created
Location: /users/42
2. Read success
GET /users/42 โ 200 OK
3. Delete success
DELETE /users/42 โ 204 No Content
4. Missing resource
GET /users/99 โ 404 Not Found
5. Authentication required
โ 401 Unauthorized
WWW-Authenticate: Bearer
6. Authorization denied
โ 403 Forbidden
7. Malformed body
POST with invalid JSON โ 400 Bad Request
8. Semantic validation
POST with age: -5 โ 422 Unprocessable Entity
9. Duplicate conflict
POST with existing email โ 409 Conflict
10. Server fault
โ 500 Internal Server Error
(no internal details in body)
Visual
Status Code Decision Flow
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Request processed โ
โ โ โ
โ โผ โ
โ Success? โ
โ โโ YES โ 2xx โ
โ โโ NO โ Client's fault? โ
โ โโ YES โ 4xx โ
โ โโ NO โ 5xx โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
2xx Selection
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Body to return? โ
โ โโ YES โ Resource created? โ
โ โ โโ YES โ 201 Created + Location โ
โ โ โโ NO โ 200 OK โ
โ โโ NO โ 204 No Content โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
4xx Selection
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Authentication valid? โ
โ โโ NO โ 401 Unauthorized โ
โ โโ YES โ Authorized? โ
โ โโ NO โ 403 Forbidden (or 404) โ
โ โโ YES โ Resource exists? โ
โ โโ NO โ 404 Not Found โ
โ โโ YES โ Syntax valid? โ
โ โโ NO โ 400 โ
โ โโ YES โ Semantic? โ
โ โโ NO โ 422 โ
โ โโ Conflict?โ
โ โโ 409 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Family and Retry
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2xx โ success, no retry โ
โ 3xx โ follow redirect โ
โ 4xx โ do not retry without changing request โ
โ 5xx โ may retry later โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Item | Value |
|---|---|
| 2xx | Success |
| 3xx | Redirection |
| 4xx | Client error |
| 5xx | Server error |
| Create | 201 + Location |
| Read | 200 |
| Delete | 204 |
| Auth missing | 401 |
| Auth denied | 403 |
| Missing resource | 404 |
| Validation | 422 |
| Server fault | 500 |
Key takeaways:
- The first digit defines the family, and the family determines the reaction. 2xx means success, 3xx means redirect, 4xx means client error, 5xx means server error. A client, a proxy, and a monitoring system all read the family before the body .
- Never return 200 for a failure. A
200with an error body forces every client to parse the body to detect errors, breaks caching and retries, and hides failures from monitoring . - 201 Created requires a Location header. The client needs to know the URI of the new resource. A
201withoutLocationis an incomplete response . - 204 No Content is the confirmation for DELETE. There is no body to parse; the status code is the signal .
- 401 and 403 are different. 401 means authentication is missing or invalid. 403 means the user is authenticated but not authorized. Returning 401 when the user is logged in confuses the client .
- 400 and 422 are different. 400 means the request cannot be parsed. 422 means it parses but violates a business rule. The distinction tells the client whether to fix the syntax or the value .
- 500 must not leak internal details. Stack traces, database errors, and file paths belong in server logs. The response body is a generic message .
Remember: The status code is the first thing every client, proxy, and monitoring system reads. It is not decorationโit is the machine-readable contract that determines whether to parse the body, retry the request, or page an engineer. The families are the coarse classification: 2xx success, 3xx redirect, 4xx client error, 5xx server error. The exact codes are the precise contract: 201 for creation with Location, 204 for deletion, 401 for missing authentication, 403 for denied authorization, 404 for missing resources, 422 for semantic validation failures, and 500 for unexpected server faults. Returning 200 for every outcome defeats the entire purpose of the protocol and makes the API impossible to monitor, cache, or retry correctly.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!