A small explainer in the spirit of Bret Victor: make the invisible visible.
HTTP is not a cloud. HTTP is not magic. HTTP is one machine sending a little text message to another machine, and getting a little text message back.
┌─────────┐ ┌─────────┐
│ Browser │ │ Server │
└────┬────┘ └────┬────┘
│ │
│ "Please give me /todos" │
│ ───────────────────────────────▶ │
│ │
│ "Sure. Here are the todos." │
│ ◀─────────────────────────────── │
│ │
That is the whole shape of HTTP:
request ─────▶
response ◀─────
When the browser wants a page, it sends a request.
GET /todos HTTP/1.1
Host: example.com
Accept: text/htmlRead it like a sentence:
GET /todos from example.com
│ │ │
│ │ └─ the machine I am talking to
│ └───────────── the thing I want
└──────────────────────── what I want to do
The method is the verb.
GET read this
POST create this
PUT replace this
PATCH change this a little
DELETE remove this
The server replies:
HTTP/1.1 200 OK
Content-Type: text/html
<h1>Todos</h1>The first number is the mood of the answer.
200 OK "Here it is."
201 Created "I made it."
204 No Content "Done, nothing to show."
400 Bad Request "I don't understand."
401 Unauthorized "Who are you?"
403 Forbidden "I know you, but no."
404 Not Found "That isn't here."
500 Server Error "I broke."
Status codes are not data. They are the server pointing at the outcome.
request: GET /cat-picture
response: 404 Not Found
The server did not send a cat.
It sent a fact about your request.
Headers are little notes attached to the message.
Content-Type: application/json
Authorization: Bearer abc123
Cache-Control: max-age=60They do not usually contain the main thing. They describe the main thing.
Content-Type "The body is JSON."
Accept "Please send JSON if you can."
Authorization "Here is my badge."
Cache-Control "You may reuse this for 60 seconds."
A message may carry a body.
When you create a todo:
POST /todos HTTP/1.1
Host: example.com
Content-Type: application/json
{
"text": "Buy milk"
}The request has two layers:
POST /todos ← intent
Content-Type: JSON ← description
{ "text": "Buy milk" } ← payload
The server might answer:
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "todo_123",
"text": "Buy milk",
"completed": false
}The client asked for a new thing. The server returned the thing as it now exists.
HTTP is stateless.
That means each request arrives alone.
Request 1: "Who am I?"
Request 2: "Who am I?"
Request 3: "Who am I?"
The server does not remember merely because you asked before. So applications add memory explicitly:
Cookie "This is the same browser as before."
Session "This browser belongs to user 42."
Bearer token "This request is authorized."
Database row "The todo still exists."
HTTP itself is forgetful. Applications build remembering on top.
HTTP:
Browser ── plain message ──▶ Server
HTTPS:
Browser ── encrypted message ──▶ Server
Same request. Same response. But outsiders cannot read or rewrite the message in transit.
If you can see this, you understand most of HTTP:
┌────────────── request ──────────────┐
│ method: POST │
│ path: /todos │
│ headers: Content-Type: JSON │
│ body: { "text": "Buy milk" } │
└─────────────────────────────────────┘
│
▼
server work
│
▼
┌────────────── response ─────────────┐
│ status: 201 Created │
│ headers: Content-Type: JSON │
│ body: { "id": "todo_123", ... } │
└─────────────────────────────────────┘
HTTP is a tiny ritual:
Say what you want.
Say what you got.
Repeat.