Networking
Requests, methods and status codes
What an HTTP request and response look like on the wire, which methods are safe and idempotent, and which status codes tell clients and proxies what to do next.
An HTTP exchange is one request and one response. The method says what the client wants. The status code says how it went. The headers carry the rules for caching, retries and identity. Two properties of methods matter most: whether they are safe and whether they are idempotent.
Concept
Before you start: a method is the verb on a request, such as GET or POST. A status code is the three-digit number on a response, such as 200 or 404. A header is a Name: value line that carries metadata.
Walking through it: one exchange
In HTTP/1.1, the messages look like this on the wire:
GET /v1/orders/42 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGciOi...
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 61
Cache-Control: private, max-age=0
ETag: "a1b2c3"
{"id":42,"status":"shipped","total_cents":4599,"currency":"USD"}The Cache-Control: private header means only the user's browser may store this response.
Safe and idempotent
- Safe means the request does not change server state. Crawlers and prefetchers assume they can send safe requests freely.
- Idempotent means sending the same request twice has the same effect as sending it once. Clients and proxies may retry idempotent requests automatically after a network error.
| Method | Safe | Idempotent | Typical use |
|---|---|---|---|
| GET | Yes | Yes | Read a resource |
| HEAD | Yes | Yes | Headers only, such as size or ETag |
| OPTIONS | Yes | Yes | Capabilities, CORS preflight |
| PUT | No | Yes | Replace a resource at a known URL |
| DELETE | No | Yes | Remove a resource; deleting twice leaves it deleted |
| POST | No | No | Create, or any non-idempotent action |
| PATCH | No | Not guaranteed | Partial update |
The classic bug: a client retries a timed-out POST /payments and charges the customer twice. Make it safe to retry with an Idempotency-Key header that the server uses to deduplicate (see idempotency). Never use GET for anything that changes state, because a link prefetcher will eventually trigger it.
Status codes that matter
| Code | Meaning | When to use it |
|---|---|---|
| 200 OK | Success with a body | Most reads and updates |
| 201 Created | Resource created | POST that creates; include Location |
| 204 No Content | Success, empty body | DELETE, or updates that return nothing |
| 301 Moved Permanently | Permanent redirect, cacheable | Old URL to new URL, forever |
| 302 Found | Temporary redirect | Login redirects. Use 307 or 308 to keep the method |
| 304 Not Modified | Your cached copy is still valid | Conditional GET with a matching ETag |
| 400 Bad Request | Malformed or invalid input | Validation failures |
| 401 Unauthorized | Not authenticated | Missing or invalid credentials |
| 403 Forbidden | Authenticated but not allowed | Permission denied |
| 404 Not Found | No such resource | Also used to hide resources from people who may not see them |
| 409 Conflict | State conflict | Duplicate create, version mismatch |
| 429 Too Many Requests | Rate limited | Include Retry-After |
| 500 Internal Server Error | Bug on the server | Unhandled exception |
| 502 Bad Gateway | Proxy got a bad response from upstream | Upstream crashed or closed the connection |
| 503 Service Unavailable | Temporarily overloaded or down | Load shedding, maintenance; include Retry-After |
| 504 Gateway Timeout | Proxy timed out waiting for upstream | Upstream too slow |
The 5xx codes point to different causes. A spike in 502s usually means app instances are crashing or closing keep-alive connections the load balancer still considers open. 504s mean the upstream is too slow. 503s mean something is shedding load on purpose.
Clients should retry 429 and 503 with backoff. They should retry 502 and 504 only for idempotent requests.
Common mistakes
- Returning 200 for errors. Retries, caches and dashboards all read the status code.
- Using 302 where the method must be kept. Use 307 or 308.
- Retrying a non-idempotent POST after a timeout. The first request may have succeeded.
Check yourself
- Why is a retried
PUTsafe but a retriedPOSTrisky? PUT replaces a resource at a known URL, so the second call leaves the same state. POST may create a second resource. - A load balancer shows a spike of 502s. What does that usually point to? Upstream instances crashing, or closing connections the load balancer still considers open.
Key takeaways
- A request has a method, URL and headers. A response has a status code, headers and body.
- Safe methods change nothing. Idempotent methods give the same result when repeated, which is what makes retries safe.
- Use status codes honestly, so retries, caches and alerts work.
Further learning
Next, see how HTTP/1.1 and HTTP/2 move these requests over connections, in HTTP/1.1 and HTTP/2 multiplexing.
MDN: HTTP lists every method and status code with examples.
Related
HTTP/1.1, HTTP/2 and HTTP/3
The protocol of the web. Separates HTTP's meaning (methods, status codes, caching) from its wire format, and shows how each version fixes the latency problem of the one before.
Idempotency and retries
Making operations safe to retry, with idempotency keys, deduplicating consumers and jittered backoff, so at-least-once delivery never means a double charge.
API design
An API is a contract that outlives the code behind it. Design the styles, methods, pagination, errors and async flows so changes stay additive.