System designCore7 min

HTTP

The language almost every service speaks: what a request and a response actually contain, which requests have the same effect when sent twice, what the status codes tell you, and what changed from HTTP/1.1 to HTTP/3.

1 · The message

An HTTP request is a short, readable letter

Take a notes app. Its phone app and its server talk in HTTP, the HyperText Transfer Protocol. When you open note 17, your phone sends a request and the server sends back a response. Stripped of encryption, both are plain text you can read:

One request, one response

http
GET /notes/17 HTTP/1.1
Host: notes.example
Accept: application/json
Cookie: session=8f3a91

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, max-age=60

{ "id": 17, "title": "Groceries", "text": "Milk, eggs" }

Part

In the example

What it says

Method

GET

What you want done

Path

/notes/17

Which thing you mean

Headers

Accept, Cookie, Cache-Control…

Everything about the message: formats, who you are, how long it may be kept

Status

200 OK

How it went

Body

The note, as JSON

The content itself; a GET request has none

That is all HTTP is: a method and a path, some headers, maybe a body, and a response with a status. Everything else on this page is about what those parts mean.

2 · Methods

The method says what you want done, and whether it is safe to repeat

Method

In the notes app

Same effect if sent twice?

GET

Read note 17

Yes: it changes nothing

POST

Create a new note

No: twice makes two notes

PUT

Replace note 17 with this text

Yes: the second time changes nothing more

PATCH

Change just the title

Not necessarily: it depends on the change

DELETE

Delete note 17

Yes: the second time there is nothing left to delete

The last column has a name. A request is idempotent if sending it twice has the same effect as sending it once. GET, PUT and DELETE are idempotent by definition; POST is not. GET is also safe, HTTP's word for a request that changes nothing; PUT and DELETE change things, so they're idempotent but not safe. Why does it matter? Because replies get lost, and clients retry:

The phone cannot tell whether the first request failed or only its answer did. Retrying a POST made a duplicate. With a payment instead of a note, it charges twice.

So design every write with the question: what happens if this arrives twice? Reads and replacements are fine. For creations and payments, the usual fix is a unique key sent with the request, so the server can recognize a repeat; Idempotency covers it in the building blocks.

3 · Status codes

The first digit of the status tells you whose fault it was

Class

Meaning

Common ones

2xx

It worked

200 OK, 201 Created, 204 No Content

3xx

Look elsewhere, or use your copy

301 and 302 redirects, 304 Not Modified

4xx

The request was wrong

400 Bad Request, 401 not signed in, 403 not allowed, 404 Not Found, 409 Conflict, 429 Too Many Requests

5xx

The server failed

500 Internal Server Error, 502, 503 Unavailable, 504 Gateway Timeout

The first digit matters most, because it tells a client what to do next:

  • 4xx: fix the request, don't just repeat it. The same bad request will fail the same way. The exception is 429, which means "slow down": wait, then try again.
  • 5xx: maybe try again later. The fault is on the server's side, and it may be temporary. Retry carefully, because a struggling server does not need a flood of retries (and remember idempotency).
  • 304: use what you have. The client asked whether its saved copy is still current, and it is. No body is sent, which saves the transfer.

4 · State

Every request stands alone

HTTP is stateless: each request carries everything the server needs, and the protocol keeps no memory between one request and the next. So how does the notes app know it is you? You tell it, every time:

After login, the server hands the phone a token in a cookie, and the phone attaches it to every later request. The server looks the token up, or checks its signature, each time.

This is a gift for scaling. Because no request depends on the one before, any server can answer it, which is what lets you run many copies behind a load balancer (see Scalability). The state has not vanished: it lives in the token and in whatever store the server checks it against.

5 · Versions

HTTP/1.1, 2 and 3 say the same things and deliver them differently

Methods, headers and status codes mean the same in every version. What changed is how the bytes travel. A notes app loading 60 small files shows the difference:

Version

How requests travel

The catch it fixed, or left

HTTP/1.1

One request at a time per connection, as readable text

Browsers open about 6 connections per site to get some parallelism

HTTP/2

Many requests interleaved on one connection, in binary, with compressed headers

Runs over TCP, so one lost packet stalls every request on the connection

HTTP/3

Over QUIC, which runs on UDP: each request is its own stream

A lost packet stalls only its own request; setup is faster; a connection survives moving from Wi-Fi to mobile data

HTTP/1.1
6 connections
HTTP/2
1 connections
HTTP/3
1 connections

Connections a browser opens to one site to fetch 60 files. With HTTP/1.1, each of the 6 handles one file at a time; with HTTP/2 and 3, all 60 share one connection.

All three are in use. As of 2026, nearly every browser supports HTTP/3, yet it still carries a minority of web traffic, and HTTP/2 and 1.1 carry the rest. For design, the lesson is the same as before: fewer connections and fewer round trips make pages faster, and newer versions are mostly ways of getting both.

Check yourself

5 questions

1. A phone sends "POST /notes" and gets no answer, so it sends it again. What might happen?
2. A client gets 400 Bad Request. What should it do?
3. HTTP is stateless. How does the notes app know who is asking?
4. What does HTTP/2 improve over HTTP/1.1, and what problem does it keep?
5. Which HTTP version is your browser most likely using for this page right now?

Takeaways

Remember this

  • An HTTP exchange is a method and path, headers, an optional body, and a response with a status.
  • GET, PUT and DELETE are idempotent; POST is not. Ask of every write: what if this arrives twice?
  • The first digit of a status says what to do: 4xx fix the request, 5xx maybe retry later, 304 use your copy.
  • HTTP is stateless: every request carries its identity, so any server can answer it.
  • HTTP/1.1, 2 and 3 mean the same things; they differ in how many connections and round trips it takes.