HTTP status codes are three-digit numbers that servers return to tell clients what happened with their request. They're the first thing you should check when debugging API issues - before looking at response bodies or logs, the status code tells you the category of the problem.
HTTP Status Codes
Standard response codes that indicate the result of an HTTP request.
Status Code Categories
The first digit tells you the category:
| Range | Category | Meaning |
|---|---|---|
| 1xx | Informational | Request received, continuing process |
| 2xx | Success | Request was successful |
| 3xx | Redirection | Client must take additional action |
| 4xx | Client Error | Problem with the request |
| 5xx | Server Error | Server failed to fulfill valid request |
Success Codes (2xx)
| Code | Name | When to Use |
|---|---|---|
| 200 | OK | Standard success. GET returned data, PUT/PATCH updated resource. |
| 201 | Created | POST successfully created a new resource. Include Location header with URL to new resource. |
| 202 | Accepted | Request accepted for processing but not completed yet. Use for async operations. |
| 204 | No Content | Success but nothing to return. Perfect for DELETE operations. |
Common mistake: Returning 200 for everything. If you create a resource, return 201. If you delete something, return 204.
Redirection Codes (3xx)
| Code | Name | When to Use |
|---|---|---|
| 301 | Moved Permanently | Resource has a new permanent URL. Search engines will update. |
| 302 | Found | Temporary redirect. Original URL should still be used. |
| 304 | Not Modified | Client's cached version is still valid. Don't send body. |
| 307 | Temporary Redirect | Like 302 but preserves request method. POST stays POST. |
| 308 | Permanent Redirect | Like 301 but preserves request method. |
Client Error Codes (4xx)
These mean the client did something wrong:
| Code | Name | When to Use |
|---|---|---|
| 400 | Bad Request | Malformed syntax, invalid JSON, missing required fields. |
| 401 | Unauthorized | No authentication provided. Token missing or invalid. |
| 403 | Forbidden | Authenticated but not allowed. User can't access this resource. |
| 404 | Not Found | Resource doesn't exist at this URL. |
| 405 | Method Not Allowed | Endpoint exists but doesn't support this HTTP method. |
| 409 | Conflict | Request conflicts with current state. Duplicate email, version conflict. |
| 422 | Unprocessable Entity | Syntax is correct but semantically invalid. Email format valid but domain doesn't exist. |
| 429 | Too Many Requests | Rate limit exceeded. Include Retry-After header. |
401 vs 403:
- 401: "Who are you?" (not authenticated)
- 403: "I know who you are, but you can't do this" (not authorized)
400 vs 422:
- 400: Can't even parse the request (invalid JSON)
- 422: Parsed OK but doesn't make sense (end_date before start_date)
Server Error Codes (5xx)
These mean the server failed:
| Code | Name | When to Use |
|---|---|---|
| 500 | Internal Server Error | Something broke. Generic "our fault" error. |
| 502 | Bad Gateway | Proxy/gateway got invalid response from upstream server. |
| 503 | Service Unavailable | Server temporarily overloaded or down for maintenance. Include Retry-After. |
| 504 | Gateway Timeout | Upstream server didn't respond in time. |
Never expose stack traces in 500 responses. Log them server-side, return a generic message to clients.
Common Mistakes
1. Using 200 for errors
ā 200 OK { "success": false, "error": "User not found" }
ā
404 Not Found { "error": "User not found" }
HTTP clients and monitoring tools rely on status codes. A 200 with an error body is invisible to them.
2. Using 500 for client errors If the user sent bad data, that's a 4xx. 500 means your code is broken. Too many 500s trigger alerts and make debugging harder.
3. Returning 200 for empty results
An empty list is still a success. GET /users?name=xyz returning zero results should be 200 with an empty array, not 404.
4. Misusing 404 404 means "this URL doesn't exist." If the URL is valid but the resource was deleted, consider 410 Gone. If the user isn't allowed to know it exists, use 403 or 404 (depending on security needs).
Best Practices
Be specific: Don't use 400 for everything. If authentication failed, use 401. If validation failed, use 422. Specific codes help clients handle errors properly.
Include helpful error bodies: Status code says what category. Body says exactly what went wrong:
{
"error": "Validation failed",
"details": [
{"field": "email", "message": "must be a valid email address"},
{"field": "age", "message": "must be at least 18"}
]
}
Use Retry-After for 429 and 503:
Tell clients when they can try again: Retry-After: 60 (seconds) or Retry-After: Wed, 21 Oct 2024 07:28:00 GMT
Document your codes: Your API docs should list which status codes each endpoint can return and what they mean in context.
Code Examples
Handling Status Codes in Fetch
async function apiCall(url) {
const res = await fetch(url);
switch (res.status) {
case 200:
case 201:
return res.json();
case 204:
return null; // No content
case 400:
const error = await res.json();
throw new ValidationError(error.details);
case 401:
// Redirect to login
window.location = '/login';
break;
case 403:
throw new Error('You do not have permission');
case 404:
throw new Error('Resource not found');
case 429:
const retryAfter = res.headers.get('Retry-After');
throw new RateLimitError(retryAfter);
case 500:
case 502:
case 503:
throw new Error('Server error. Please try again later.');
default:
throw new Error(`Unexpected status: ${res.status}`);
}
}Related Terms
CORS
Cross-Origin Resource Sharing - A security mechanism that controls how web pages can request resources from different domains.
Service Virtualization
An enterprise-grade technique for simulating the behavior of dependent services, APIs, and systems that are unavailable or costly to access.
Rate Limiting
A technique to control the number of API requests a client can make within a time window.
Query Parameters
Key-value pairs appended to URLs for filtering, sorting, and customizing API requests.