HTTP Methods and Status
HTTP Status Codes: 1xx through 5xx
Read aloud is unavailable in this browser.
The Server's Vocabulary for Every Situation
When a server receives an HTTP request, it must communicate not just what it's returning, but how the request was processed. Did it succeed? Did something go wrong? Should the client try somewhere else? This communication happens through HTTP status codes—a three-digit numeric vocabulary that has evolved over three decades of web development.
Status codes are the first line of every HTTP response:
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
HTTP/1.1 500 Internal Server Error
The first digit indicates the category of response, and the remaining two digits provide specificity within that category. Understanding status codes is essential for building reliable APIs, debugging web applications, and implementing proper error handling.
By the end of this page, you will: • Understand all five status code categories (1xx-5xx) • Master the most important codes in each category • Know when to use each status code in API design • Handle status codes correctly in client applications • Debug HTTP issues using status code semantics
Status Code Structure and Categories
HTTP status codes follow a systematic structure defined by RFC 9110. The three-digit code consists of:
- First digit (1-5): The response class
- Second and third digits: Specific meaning within the class
The reason phrase (e.g., "OK", "Not Found") is human-readable but has no semantic meaning—clients should not parse it.
| Class | Range | Category | Description |
|---|---|---|---|
| 1xx | 100-199 | Informational | Request received, processing continues |
| 2xx | 200-299 | Success | Request received, understood, accepted |
| 3xx | 300-399 | Redirection | Further action needed to complete request |
| 4xx | 400-499 | Client Error | Request contains error or cannot be fulfilled |
| 5xx | 500-599 | Server Error | Server failed to fulfill valid request |
The Significance of Categories
The category structure enables generic error handling. A client that doesn't recognize a specific code can fall back to category-level behavior:
418 I'm a teapot → Unknown, but 4xx → Client error → Fix the request
507 Insufficient Storage → Unknown, but 5xx → Server error → Retry later
Status Line Anatomy
HTTP/1.1 404 Not Found
├──────┘ └─┘ └────────┘
│ │ └── Reason Phrase (informational only)
│ └── Status Code (machine-readable)
└── HTTP Version
Important: In HTTP/2 and HTTP/3, the reason phrase is not transmitted—only the status code. Design your systems to rely solely on the numeric code.
1xx Informational Responses
1xx codes are interim responses indicating that the server has received the request and is continuing to process it. These are rare in typical web browsing but important in advanced scenarios.
| Code | Name | Use Case |
|---|---|---|
| 100 | Continue | Server received headers; client should send body |
| 101 | Switching Protocols | Server agrees to protocol change (e.g., WebSocket upgrade) |
| 102 | Processing (WebDAV) | Server is processing but no response yet available |
| 103 | Early Hints | Server sending preliminary headers before final response |
100 Continue
When a client wants to send a large request body, it can first send:
POST /upload HTTP/1.1
Host: example.com
Content-Length: 10485760
Expect: 100-continue
(No body yet)
The server can respond:
100 Continue→ "Send the body, I'll accept it"417 Expectation Failed→ "Don't send; I'll reject it anyway"
This prevents wasting bandwidth on uploads that would be rejected (e.g., file too large, unauthorized).
101 Switching Protocols
Used when upgrading from HTTP to WebSocket:
# Client Request
GET /chat HTTP/1.1
Host: example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13
# Server Response
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
After this exchange, the connection switches to WebSocket protocol.
103 Early Hints
A newer code (RFC 8297) that allows servers to send headers before the final response:
HTTP/1.1 103 Early Hints
Link: </styles.css>; rel=preload; as=style
Link: </script.js>; rel=preload; as=script
(Server continues processing...)
HTTP/1.1 200 OK
Content-Type: text/html
...
Browsers can start preloading resources while waiting for the final response.
Most web developers rarely encounter 1xx codes directly because:
• HTTP libraries handle 100 Continue automatically • WebSocket libraries abstract 101 Switching Protocols • 103 Early Hints is relatively new and server-specific
However, understanding them is crucial for debugging low-level HTTP issues.
2xx Success Responses
2xx codes indicate successful request processing. The specific code communicates how the request succeeded, which affects client behavior regarding caching, redirects, and data handling.
| Code | Name | When to Use |
|---|---|---|
| 200 | OK | Standard success response with body |
| 201 | Created | Resource successfully created (include Location) |
| 202 | Accepted | Request accepted for async processing |
| 203 | Non-Authoritative Information | Transformed by proxy |
| 204 | No Content | Success but no body to return |
| 205 | Reset Content | Success; client should reset document view |
| 206 | Partial Content | Range request fulfilled |
| 207 | Multi-Status (WebDAV) | Multiple operations with mixed results |
| 208 | Already Reported (WebDAV) | Members already enumerated |
| 226 | IM Used | Delta encoding applied |
200 OK
The default success code. Request received, understood, and processed:
HTTP/1.1 200 OK
Content-Type: application/json
{"status": "success", "data": {...}}
Use for: GET/POST/PUT/PATCH/DELETE that succeed and have a response body.
201 Created
A new resource was created as a result of the request:
POST /api/users HTTP/1.1
{"name": "Alice"}
HTTP/1.1 201 Created
Location: /api/users/12345
Content-Type: application/json
{"id": 12345, "name": "Alice", "createdAt": "2025-01-18T12:00:00Z"}
Key requirements:
- Include
Locationheader pointing to new resource - Response body typically contains the created resource
- Used only when a new resource is created (not updated)
202 Accepted
Request accepted but not yet processed—ideal for async operations:
POST /api/reports/generate HTTP/1.1
{"type": "annual", "year": 2024}
HTTP/1.1 202 Accepted
Location: /api/reports/jobs/abc123
Content-Type: application/json
{
"jobId": "abc123",
"status": "queued",
"statusUrl": "/api/reports/jobs/abc123",
"estimatedCompletion": "2025-01-18T12:10:00Z"
}
Clients should poll the status URL or use webhooks.
204 No Content
Success with no response body needed:
DELETE /api/users/12345 HTTP/1.1
HTTP/1.1 204 No Content
Common uses:
- Successful DELETE operations
- Update operations where client doesn't need the result
- Acknowledgment responses
Important: 204 responses MUST NOT include a body. The Content-Length should be 0 or absent.
206 Partial Content
Used with range requests—essential for video streaming and download resumption:
GET /video.mp4 HTTP/1.1
Range: bytes=1000-1999
HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Content-Range: bytes 1000-1999/1000000
Content-Length: 1000
(1000 bytes of video data)
This enables:
- Video seeking without downloading entire file
- Resumable downloads after interruption
- Parallel downloading (multiple ranges simultaneously)
200 OK: Default for GET, and for POST/PUT/PATCH/DELETE when returning data
201 Created: POST that creates a new resource (not updating existing)
204 No Content: DELETE, or any operation where the client doesn't need response data
Why it matters: Some HTTP libraries treat 204 as success without trying to parse a body. Returning 200 with an empty body may cause parsing errors in some clients.
3xx Redirection Responses
3xx codes indicate that the client must take additional action to complete the request—typically following a redirect to a different URL.
| Code | Name | Method Preservation | Use Case |
|---|---|---|---|
| 300 | Multiple Choices | N/A | Multiple options; client chooses |
| 301 | Moved Permanently | May change to GET | Permanent URL change (SEO-friendly) |
| 302 | Found | May change to GET | Temporary redirect (historical) |
| 303 | See Other | Always GET | Redirect after POST (PRG pattern) |
| 304 | Not Modified | N/A | Resource unchanged; use cache |
| 307 | Temporary Redirect | Preserved | Temporary; must keep method |
| 308 | Permanent Redirect | Preserved | Permanent; must keep method |
301 Moved Permanently
The resource has permanently moved to a new URL:
GET /old-page HTTP/1.1
HTTP/1.1 301 Moved Permanently
Location: https://example.com/new-page
Implications:
- Search engines transfer SEO value to new URL
- Browsers may cache the redirect indefinitely
- Bookmarks and links should be updated
Caveat: Historically, browsers would change POST to GET on 301. Use 308 if method preservation is required.
302 Found (Temporary Redirect)
The resource is temporarily at a different URL:
GET /seasonal-sale HTTP/1.1
HTTP/1.1 302 Found
Location: /winter-sale-2025
Implications:
- Search engines don't transfer SEO value
- Browsers don't cache the redirect
- Original URL should still work later
Historical note: 302 originally meant "keep the method," but browsers incorrectly changed POST to GET. 307 was created to fix this.
303 See Other
After processing a POST, redirect to a GET-able result:
POST /orders HTTP/1.1
{"items": [...]}
HTTP/1.1 303 See Other
Location: /orders/12345
This implements the Post/Redirect/Get (PRG) pattern, preventing duplicate form submissions on refresh.
- •Resource temporarily elsewhere
- •Method MUST be preserved
- •POST stays POST
- •Safe for API redirects
- •Not cached by default
- •Resource permanently moved
- •Method MUST be preserved
- •POST stays POST
- •Safe for API migrations
- •Browsers cache indefinitely
304 Not Modified
Used with conditional requests to indicate cached content is still valid:
GET /resource HTTP/1.1
If-None-Match: "etag-abc123"
HTTP/1.1 304 Not Modified
ETag: "etag-abc123"
Cache-Control: max-age=3600
Key points:
- No body is sent (saves bandwidth)
- Client uses its cached copy
- Any headers that would change the cached response should be included
Redirect Decision Tree
Need to redirect?
├── Permanent change?
│ ├── Yes → Method preservation needed?
│ │ ├── Yes → 308 Permanent Redirect
│ │ └── No → 301 Moved Permanently
│ └── No → Method preservation needed?
│ ├── Yes → 307 Temporary Redirect
│ └── No → After POST? → 303 See Other
│ Otherwise → 302 Found
A redirect loop occurs when A redirects to B, and B redirects back to A (directly or through a chain). Browsers typically detect this after 20-50 redirects and display an error.
Common causes: • Misconfigured HTTP→HTTPS redirects • CDN/origin misconfiguration • Cookie-based redirects for logged-out users
Always test redirect changes carefully!
4xx Client Error Responses
4xx codes indicate the client sent a request the server cannot or will not process. These are client errors—the solution requires the client to change something.
| Code | Name | Meaning |
|---|---|---|
| 400 | Bad Request | Malformed request syntax or invalid data |
| 401 | Unauthorized | Authentication required or failed |
| 403 | Forbidden | Authenticated but not authorized |
| 404 | Not Found | Resource does not exist |
| 405 | Method Not Allowed | HTTP method not supported for this resource |
| 406 | Not Acceptable | Cannot satisfy Accept headers |
| 409 | Conflict | Request conflicts with current state |
| 410 | Gone | Resource permanently removed |
| 415 | Unsupported Media Type | Content-Type not supported |
| 422 | Unprocessable Entity | Semantically invalid (WebDAV, commonly used) |
| 429 | Too Many Requests | Rate limit exceeded |
400 Bad Request
The generic client error—the request is malformed or invalid:
POST /api/users HTTP/1.1
Content-Type: application/json
{invalid json
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Bad Request",
"message": "Invalid JSON in request body",
"details": {
"line": 1,
"column": 2,
"expected": "property name"
}
}
Use for:
- Malformed JSON/XML
- Missing required parameters
- Invalid parameter types or formats
- Any syntax-level error
401 Unauthorized vs. 403 Forbidden
This distinction confuses many developers:
401 Unauthorized: "Who are you?" — Authentication missing or failed
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
{"error": "Authentication required"}
Client should provide/fix credentials.
403 Forbidden: "I know who you are, but no." — Authenticated but not authorized
HTTP/1.1 403 Forbidden
{"error": "You do not have permission to access this resource"}
Re-authenticating won't help; user needs different permissions.
403 also used for: Requests that are always forbidden regardless of authentication (e.g., accessing an internal-only endpoint from public internet).
404 Not Found
The most famous HTTP status code—resource doesn't exist:
GET /api/users/99999999 HTTP/1.1
HTTP/1.1 404 Not Found
{"error": "User not found"}
Security consideration: Sometimes you should return 404 instead of 403 to avoid revealing that a resource exists. Example: checking if a username is taken during registration.
409 Conflict
The request conflicts with the current state of the resource:
# Optimistic locking failure
PUT /api/documents/123 HTTP/1.1
If-Match: "old-etag"
HTTP/1.1 409 Conflict
{"error": "Document has been modified by another user"}
Use for:
- Optimistic concurrency conflicts
- Duplicate resource creation attempts
- Business rule violations (e.g., "Can't delete user with active orders")
422 Unprocessable Entity
The request is syntactically correct but semantically invalid:
POST /api/users HTTP/1.1
{"email": "not-an-email", "age": -5}
HTTP/1.1 422 Unprocessable Entity
{
"error": "Validation failed",
"details": [
{"field": "email", "message": "Invalid email format"},
{"field": "age", "message": "Must be a positive number"}
]
}
400 vs 422:
- 400: "I can't parse your request" (syntax error)
- 422: "I parsed it, but it doesn't make sense" (semantic error)
When rate limiting, always include Retry-After header:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705590000
{"error": "Rate limit exceeded. Retry after 60 seconds."}
Clients should respect Retry-After to avoid worsening the situation.
Other Notable 4xx Codes
| Code | Name | Use Case |
|---|---|---|
| 405 | Method Not Allowed | Server should include Allow header with valid methods |
| 406 | Not Acceptable | Can't satisfy Accept headers (content negotiation failure) |
| 408 | Request Timeout | Client took too long to send the request |
| 410 | Gone | Resource existed but permanently removed (stronger than 404) |
| 411 | Length Required | Server requires Content-Length header |
| 412 | Precondition Failed | If-Match, If-Unmodified-Since failed |
| 413 | Payload Too Large | Request body exceeds server limits |
| 414 | URI Too Long | URL exceeds server limits (maybe use POST?) |
| 415 | Unsupported Media Type | Server doesn't support the Content-Type |
| 418 | I'm a teapot | April Fools' joke; do not use in production |
| 451 | Unavailable For Legal Reasons | Censorship/legal block (named after Fahrenheit 451) |
5xx Server Error Responses
5xx codes indicate the server failed to fulfill a valid request. The problem is on the server side—the client request was fine. These are the errors that wake operations teams at 3 AM.
| Code | Name | Meaning |
|---|---|---|
| 500 | Internal Server Error | Generic server-side failure |
| 501 | Not Implemented | Server doesn't support this functionality |
| 502 | Bad Gateway | Upstream server returned invalid response |
| 503 | Service Unavailable | Server temporarily overloaded or down |
| 504 | Gateway Timeout | Upstream server didn't respond in time |
| 505 | HTTP Version Not Supported | Server doesn't support HTTP version |
| 507 | Insufficient Storage (WebDAV) | Server storage exhausted |
| 508 | Loop Detected (WebDAV) | Infinite loop detected |
| 511 | Network Authentication Required | Captive portal (hotel WiFi, etc.) |
500 Internal Server Error
The catch-all for server-side failures:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Internal Server Error",
"requestId": "abc123",
"message": "An unexpected error occurred"
}
Best practices:
- Never expose stack traces to clients (security risk)
- Include a request ID for debugging (correlate with server logs)
- Log the full error internally
- Return a generic message to users
502 Bad Gateway
A reverse proxy/load balancer couldn't get a valid response from upstream:
[Client] → [Nginx] → [App Server]
↓
App Server returns:
- Malformed response
- Connection reset
- Protocol error
↓
Nginx returns 502 to client
Common causes:
- Application crash during request processing
- Upstream server misconfiguration
- Protocol mismatch (HTTP/1.1 vs HTTP/2)
503 Service Unavailable
Server is temporarily unable to handle requests:
HTTP/1.1 503 Service Unavailable
Retry-After: 300
{"error": "Service temporarily unavailable", "retryAfter": 300}
Use for:
- Planned maintenance windows
- Server overloaded (too many requests)
- Dependency unavailable (database down)
Important: Include Retry-After header so clients know when to retry.
504 Gateway Timeout
The gateway didn't receive a response from upstream in time:
[Client] → [Load Balancer] → [App Server]
↓
Waits 60 seconds...
No response from App Server
↓
Returns 504 to client
Common causes:
- Long-running queries without timeout
- Deadlocked processes
- Network partition between gateway and upstream
- Upstream server too slow
502 vs 503 vs 504
| Code | Problem | Solution |
|---|---|---|
| 502 | Upstream returned garbage | Fix upstream app |
| 503 | Server overwhelmed or down | Wait and retry |
| 504 | Upstream is too slow | Increase timeout or optimize app |
Best Practices for 5xx Handling
Server-side:
- Log everything — Include request ID, stack trace, context
- Sanitize responses — Never expose internal details
- Use appropriate codes — Don't return 500 for everything
- Set Retry-After for 503 — Guide client behavior
- Monitor and alert — 5xx spikes indicate problems
Client-side:
- Implement retry logic — With exponential backoff
- Respect Retry-After — Don't pound a struggling server
- Log the request ID — For debugging with API provider
- Have fallback behavior — Graceful degradation
Don't return 500 for client errors:
Wrong:
// Status: 500
{"error": "Invalid email format"}
Right:
// Status: 400 or 422
{"error": "Invalid email format", "field": "email"}
Returning 500 for validation errors confuses monitoring (real server issues get lost in noise), breaks client retry logic (shouldn't retry client errors), and misrepresents the problem.
Status Code Selection Guide
Choosing the right status code is a design decision. This section provides quick reference guides for common scenarios.
| Operation | Success | Not Found | Error |
|---|---|---|---|
| GET resource | 200 OK | 404 Not Found | 400/500 |
| POST create | 201 Created | N/A | 400/409/422 |
| POST action | 200 OK / 202 Accepted | 404 Not Found | 400/422/500 |
| PUT update | 200 OK / 204 No Content | 404 Not Found | 400/409/422 |
| PUT create | 201 Created | N/A | 400/409 |
| PATCH update | 200 OK | 404 Not Found | 400/409/422 |
| DELETE | 200 / 204 / 202 | 404 (optional) | 409 |
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
function chooseStatusCode(request, result) { // Success cases if (result.success) { if (request.method === 'POST' && result.resourceCreated) { return 201; // Created } if (result.asyncProcessing) { return 202; // Accepted } if (result.noContent || request.method === 'DELETE') { return 204; // No Content } return 200; // OK } // Client errors if (result.validationError) { return result.syntaxError ? 400 : 422; } if (result.authenticationRequired) { return 401; // Unauthorized } if (result.permissionDenied) { return 403; // Forbidden } if (result.resourceNotFound) { return 404; // Not Found } if (result.conflict) { return 409; // Conflict } if (result.rateLimited) { return 429; // Too Many Requests } // Server errors if (result.serverError) { if (result.upstreamError) { return 502; // Bad Gateway } if (result.overloaded) { return 503; // Service Unavailable } if (result.upstreamTimeout) { return 504; // Gateway Timeout } return 500; // Internal Server Error }}KEEP LEARNING
There’s more to understand.
You’re reading the introduction. Create a free account to read the complete lesson, save notes and keep track of your progress.