HTTP Status Codes Explained: Every Code With Real-World Examples and When to Use Each

HTTP Status Codes Explained: Every Code With Real-World Examples and When to Use Each

Returning the wrong HTTP status code is one of the most common API design mistakes. Returning 200 for errors, 404 when 403 is correct, or 500 when 422 would be more helpful — these mistakes make APIs harder to use and debug. This guide covers every status code that matters, with real examples and the common mistakes to avoid.

TL;DR: 200=OK, 201=Created(+Location), 204=No Content, 301=Permanent Redirect, 304=Not Modified, 400=Bad Syntax, 401=Unauthenticated, 403=Unauthorized, 404=Not Found, 409=Conflict, 422=Validation Failed, 429=Rate Limited, 500=Server Bug, 502=Bad Gateway, 503=Service Unavailable.

2xx — Success codes

// 200 OK — general success, includes response body
GET /users/123 → 200 { id: 123, name: "Alice" }
PUT /users/123 → 200 { id: 123, name: "Alice Updated" }

// 201 Created — resource was created, include Location header
POST /users → 201
Location: /users/124
{ id: 124, name: "Bob" }

// 202 Accepted — request accepted, processing asynchronously
POST /reports/generate → 202
{ jobId: "job-abc-123", statusUrl: "/jobs/job-abc-123" }
// Client polls /jobs/job-abc-123 for completion

// 204 No Content — success with NO response body
DELETE /users/123 → 204 (empty body)
PUT /users/123/preferences → 204 (when you don't return updated resource)
// Never return body with 204 — clients won't read it

3xx — Redirection codes

// 301 Moved Permanently — resource moved, update bookmarks
// Browser caches redirect: subsequent requests go directly to new URL
GET /api/v1/users → 301 Location: /api/v2/users

// 302 Found — temporary redirect (do NOT cache)
// Use for: temporary maintenance page, login redirects

// 304 Not Modified — conditional request, use cached version
// Client sends: If-None-Match: "etag-abc"
// Server: content unchanged → 304 (empty body, client uses cache)
// Massive bandwidth saving for static assets

// 307 Temporary Redirect — preserve HTTP method (unlike 302)
// POST to /login → 307 → POST forwarded to new URL

// 308 Permanent Redirect — preserve method (like 301 but keeps POST)

4xx — Client error codes

// 400 Bad Request — malformed syntax, invalid JSON, missing required field
POST /users { name: null } → 400 { error: "name is required" }

// 401 Unauthorized — NOT authenticated (confusing name)
// Missing or invalid token
GET /profile → 401 { error: "Authentication required" }
WWW-Authenticate: Bearer

// 403 Forbidden — authenticated but NOT authorized
// User IS logged in but lacks permission
GET /admin/users → 403 { error: "Insufficient permissions" }

// 404 Not Found — resource does not exist
// Also use when you want to hide existence of forbidden resources
GET /users/999 → 404 { error: "User not found" }

// 409 Conflict — state conflict
POST /users { email: "existing@email.com" } → 409 { error: "Email already exists" }
PUT /orders/123 { version: 1 } → 409 { error: "Conflict: order was modified" }

// 422 Unprocessable Entity — valid syntax, invalid semantics
// JSON is valid but fails business rule validation
POST /users { age: -5 } → 422 { error: "Age must be positive" }

// 429 Too Many Requests — rate limited
GET /api/search → 429
Retry-After: 60
X-RateLimit-Reset: 1712534400

5xx — Server error codes

// 500 Internal Server Error — bug in your code
// Client did nothing wrong, you have a bug
// Log the full error server-side, return generic message to client
GET /users → 500 { error: "Something went wrong" }
// NEVER expose stack traces, DB queries, or internal paths to clients

// 502 Bad Gateway — upstream server returned invalid response
// Your server is fine, upstream (DB, microservice) returned garbage

// 503 Service Unavailable — server temporarily down
// Maintenance, overloaded, or circuit breaker open
GET /api → 503
Retry-After: 120
{ error: "Service temporarily unavailable" }

// 504 Gateway Timeout — upstream took too long
// Your server waited too long for DB or microservice

Common mistakes to avoid

  • ❌ 200 for errors — never return { status: 200, error: "Not found" }
  • ❌ 404 when 403 is correct — leaks resource existence; sometimes intentional
  • ❌ 400 for validation failures — use 422 for business rule violations
  • ❌ 500 for client errors — 500 means YOUR code has a bug, not theirs
  • ❌ 200 with empty body — use 204 when there is no content to return
  • ✅ 201 + Location header on resource creation
  • ✅ 429 + Retry-After for rate limiting
  • ✅ 401 + WWW-Authenticate for unauthenticated requests

Status codes are foundational to the REST API design guide — every design decision there depends on using the right status code. External reference: MDN HTTP status codes reference.

Recommended Reading

Designing Data-Intensive Applications — The essential book every senior developer needs. Covers distributed systems, databases, and production architecture.

The Pragmatic Programmer — Timeless engineering wisdom for writing better, more maintainable code at any level.

Affiliate links. We earn a small commission at no extra cost to you.

Free Weekly Newsletter

🚀 Don’t Miss the Next Cheat Code

Join 1,000+ senior developers getting expert-level JS, Python, AWS, system design and AI secrets every week. Zero fluff, pure signal.

✓ No spam✓ Unsubscribe anytime✓ Expert-level only

Discover more from CheatCoders

Subscribe to get the latest posts sent to your email.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply