← Computer Networks
DNS & the Web Application Layer

HTTP — Methods, Headers & Status Codes

Watch: "HTTP Status Codes Explained In 5 Minutes" — ByteByteGo

HTTP is the contract layer underneath nearly every API you'll design or consume. Interviewers use method semantics and status codes as a quick proxy for whether you build APIs that are safe to retry, cache, and reason about under failure. It's a plain-text (in HTTP/1.1) request/response protocol at the application layer — you can read one on the wire, which is exactly what makes it worth actually looking at rather than just memorizing a table.

What Is HTTP?

HTTP (HyperText Transfer Protocol) is the language a browser or app uses to ask a server for something — a web page, a photo, a bank balance — and the language the server uses to answer back. Every request follows the same shape: an action ("get me this" or "create that"), a target, and some extra details, and every response comes back with a code that says whether it worked. It's the plumbing behind almost every "load" or "submit" you do online.

Where This Is Used

A Day-to-Day Example

Think of ordering at a restaurant counter. You (the client) state a clear request — "one coffee, medium, oat milk" — and the person behind the counter (the server) either hands it back with a confirmation that it's ready, or tells you why not: they're out of oat milk, the register's down, or you need to join a different line first. HTTP status codes are just that response, standardized: success, "you asked wrong," or "we messed up."

Deep Dive: Anatomy of a Request and a Response

A request is a method + path/URL + headers + optional body. A response is a status line + headers + optional body. Here's a realistic pair for fetching a user resource:

Two HTTP request/response exchangesClientapi.example.comGET /users/123 + headersmethod, path, auth200 OK + headers + JSON bodystatus, caching, ETagPOST /orders + Idempotency-Keybody = new order201 Created, Location: /orders/9981where it now lives
Every HTTP exchange is one request (method, path, headers, optional body) and one response (status code, headers, optional body). The full messages are shown below.
requestresponse
GET /users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Accept: application/json
User-Agent: curl/8.4.0

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 87
Cache-Control: private, max-age=60
ETag: "a1b2c3d4"

{"id":123,"name":"Ada Lovelace","email":"[email protected]","role":"admin"}

And a create operation, which is the case where method semantics actually change your system's correctness:

POST /orders HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
Idempotency-Key: 8f14e45f-ceea-4d6b-9c3f-abc123

{"sku":"WIDGET-1","qty":2}

HTTP/1.1 201 Created
Location: /orders/9981
Content-Type: application/json

{"id":9981,"sku":"WIDGET-1","qty":2,"status":"pending"}

Note the Location header on 201 Created — it points at the newly created resource, and the Idempotency-Key header is an application-level convention (not built into HTTP itself) that lets the server recognize "this is a retry of the same logical request" and return the original result instead of creating a second order.

Deep Dive: Idempotency, Concretely

Idempotent means: calling it once or calling it five times in a row leaves the system in the same final state. GET is idempotent because it doesn't change state at all. PUT /users/123 with the same full body is idempotent — sending it three times still leaves user 123 with exactly that data. DELETE /users/123 is idempotent by convention — the end state ("user 123 doesn't exist") is the same whether you call it once or five times, even though the second and later calls should probably return 404 rather than 204. POST /orders is not idempotent — calling it twice creates two orders, which is exactly why payment and order-creation APIs need an explicit idempotency key: the client generates a unique key per logical operation, sends it on every retry attempt, and the server deduplicates by that key rather than by the network call itself.

Key Pointers

How It Works

  1. The client builds a request line (method + path + version), headers, and an optional body.
  2. The client sends it over an already-established TCP/TLS (or QUIC) connection.
  3. The server parses the request and routes it to a handler based on method and path.
  4. The handler executes and returns a status line, headers, and an optional response body.
  5. The client reads the status code's category first to decide whether to use the response, retry, or follow a redirect.

Try It Yourself

# Full request/response including headers, timing, and the TLS handshake
curl -v https://example.com

# Just the response headers (fast way to check Content-Type, Cache-Control, ETag)
curl -I https://example.com

# Send a conditional GET using a previously seen ETag — expect 304 Not Modified
curl -H 'If-None-Match: "a1b2c3d4"' -v https://api.example.com/users/123

# Explicit method + JSON body, mimicking a real POST
curl -X POST https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8f14e45f-ceea-4d6b-9c3f-abc123" \
  -d '{"sku":"WIDGET-1","qty":2}'

# In browser DevTools: Network tab → click any request → Headers tab
# shows the exact request/response headers and status code the browser saw

Interview Q&A

Q: Why does idempotency matter for a payments API specifically?

A: Networks fail in ambiguous ways — a client can time out waiting for a response even though the server successfully processed the request and the response just got lost. If the client blindly retries a plain POST /charge, the customer could be charged twice for one purchase. An idempotency key breaks that ambiguity: the server remembers it already processed that key and returns the original result on retry instead of charging again.

Q: When would you return 409 instead of 400?

A: 400 is for a malformed or invalid request on its own terms — bad JSON, a missing required field. 409 Conflict is for a request that's well-formed but conflicts with the current state of the resource — e.g. trying to create a user with an email that already exists, or a concurrent update that violates an optimistic-locking version check.

Q: Your API is returning 200 OK with {"error": "not found"} in the body. What's wrong with that?

A: It breaks anything that relies on the status code for control flow — caches will happily cache an "error" as if it were valid data, retry logic won't know to retry, and monitoring/alerting built on status-code metrics will silently miss the failure. The status code should reflect the actual outcome; this case should be a 404.

Q: How should a client handle a 429 response?

A: Read the Retry-After header if present and back off for at least that long before retrying, ideally with jitter added so many clients don't retry in lockstep. 429 means the request was understood and could have succeeded, but the client is being throttled — treating it like a hard failure (and giving up) or like a transient network blip (and retrying immediately) are both wrong.

Q: Is PATCH idempotent?

A: Not by default. PATCH {"balance": "+10"} applied twice gives a different result than applied once, so it's not idempotent. PATCH {"status": "shipped"} applied twice gives the same result, so that particular patch happens to be idempotent — but the method itself makes no guarantee either way, unlike PUT where idempotency is part of the contract.

System Design Tie-in

Method and status-code discipline is one of the first things interviewers check when they ask you to design a public API. Idempotency keys come up directly in any "design a payment system" or "design a ride-booking system" prompt — you're expected to volunteer that write-heavy, retry-prone endpoints need one. Status codes drive retry logic in every service mesh and client SDK: 5xx and 429 are usually retryable (with backoff), 4xx generally isn't (the request itself is wrong, retrying won't fix it) — this distinction is exactly what a circuit breaker or retry policy in a distributed system is built around. Cache-Control/ETag headers are the mechanism a CDN or reverse proxy uses to decide whether it can serve a cached response without hitting origin at all.

Trade-offs

The most common interview pitfall is treating POST as safely retryable without an idempotency key — a network timeout followed by a client retry can create duplicate resources. Another is returning 200 OK with an error payload instead of a proper 4xx/5xx, which breaks anything relying on status codes for control flow (caches, retries, monitoring). Use 429 Too Many Requests with a Retry-After header for rate limiting rather than a generic 400, and be consistent about 400 (malformed/invalid input) versus 404 (resource genuinely doesn't exist) versus 422 (well-formed but semantically invalid).