APIer/01 · HTTP fundamentals
CHAPTER 01 · Methods, status codes, headers

The HTTP message, line by line

Every API call is one HTTP request and one HTTP response. A request carries a method, a target, headers, and an optional body. A response carries a status code, headers, and an optional body. This chapter reads both, part by part.

§01

The URL: which server, which resource

A URL says where the request goes and which resource it asks for. It splits into parts, and each part does one job. Click a part to read what it does.

/productsPath · collection

A collection of resources: all products. The name is a plural noun. There is no verb in the path, because the verb is the HTTP method: GET /products means read the products. Section 03 covers methods.

How to read any URL

Read it from left to right: how the message is sent (the scheme) → which server receives it (the host) → which resource (the path) → what options apply (the query string). However long a URL is, it splits along those four boundaries.

§02

Message anatomy: what a request actually looks like

The browser, fetch, and curl all send the same thing: an HTTP message. In HTTP/1.1 that message is plain text, so you can read it directly.

Here is a complete request message. This one does not read a product. It creates one, so it carries a body.

Request message
1POST /v1/products HTTP/1.1
2Host: api.shop.com
3Content-Type: application/json
4Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
5
6{ "name": "Mechanical keyboard", "price": 399 }
The highlighted first line is the request line: method, target, and HTTP version. After it come the headers, one blank line, and the body.
Line 1
Request line

POST /v1/products HTTP/1.1 — the method says what to do, the target says which resource, and the version says which rules both sides follow.

Lines 2 to 4
Header block

One header per line, written as Name: value. Headers carry metadata: which host the request is for (Host), what format the body uses (Content-Type), and who is calling (Authorization).

Line 5
One blank line

The blank line marks the end of the headers and the start of the body. It is the only marker a parser has, so it is never optional.

After the blank line
Body

The data being sent, here a piece of JSON. A real request also sends Content-Length (or uses chunked transfer encoding) so the receiver knows how many bytes the body has. A GET request normally has no body, because it only asks to read something.

The server replies with a response message. The structure is the same. Only the first line changes: instead of saying what to do, it reports what happened.

Response message
1HTTP/1.1 201 Created
2Content-Type: application/json
3Location: /v1/products/43
4
5{ "id": 43, "name": "Mechanical keyboard", "price": 399 }
The status line carries the HTTP version, the status code, and a short reason phrase. 201 Created means a new resource was created, and the Location header gives its address.

HTTP/1.1 messages are text; HTTP/2 and HTTP/3 are not

The two blocks above are not diagrams. That is the exact text an HTTP/1.1 client puts on the connection, which is why you can type a request by hand in a terminal and get a real response back. HTTP/2 and HTTP/3 replace the text with a compressed binary format, but they carry the same parts: a method, a target, headers, a status code, and a body. Learn to read the parts, and the wire format stops mattering.

§03

Methods: what the request wants to do

The target says which resource. The method says what to do with it. There are only a few methods, and each one comes with a promise.

MethodMeaningSafeIdempotentNotes
GETRead the resource.No body. The response can be cached.
POSTSend data for the server to process. Most often: create a new resource.Sending it twice can create two resources.
PUTReplace the resource with the body you send.Sending the same body again leaves the same state.
PATCHChange part of the resource.The specification does not promise idempotence.
DELETERemove the resource.After one delete or five, the resource is gone.
HEADSame as GET, but the response has no body.Used to check whether a resource exists, and how large it is.
OPTIONSAsk which methods the target supports.Used by the CORS preflight request. Chapter 06.

Those two columns are the important part of this section. Safe means the request is not meant to change anything on the server. Idempotent means that sending the same request once or many times leaves the server in the same state. Idempotence is about the effect, not about the reply: a second DELETE may answer 404 while the effect is unchanged. Every safe method is idempotent. The reverse is not true — PUT writes data, so it is not safe, but writing the same body again produces the same state, so it is idempotent.

Why idempotence matters: you can retry

You send a request and the connection times out. You do not know whether the server never received it, or handled it and lost the reply. With an idempotent method you can send it again, because the state ends up the same either way. With POST you cannot: if the first attempt succeeded, the retry creates a second order or charges the card twice.

This also settles a common question. “The second DELETE returns 404 — is it still idempotent?” Yes. Idempotence is defined by the effect on the server, not by the status code. After one delete and after two, the resource is gone.

PUT and PATCH: the pair people mix up

PUT replaces the whole resource. If you send half the object, the fields you left out are removed. That is how an email address or a bio disappears from a profile. PATCH changes only the fields you mention. PATCH is also not idempotent in general: a patch meaning “add 1 to the stock count” adds 2 when it runs twice. To change a few fields, use PATCH. To replace the resource, use PUT and send the complete object.

Pick the method: five situations0 / 5 correct

1Open a product page and show the details of product 42.

2A user fills in the form and creates a new account.

3Replace the whole profile of user 42 with a new, complete one.

4A user wants to change only the nickname and leave every other field as it is.

5A moderator removes a comment that breaks the rules.

§04

Status codes: the first line of the reply

Three digits. The first digit tells you what kind of answer this is. Learn the five families first, then the individual codes.

1xx
Informational

Received, still working. You will rarely meet these.

2xx
Success

It worked. 200 returns a body, 201 created a resource, 202 accepted the work but has not finished it, 204 succeeded with no body.

3xx
Redirection

Look somewhere else. 301 moved permanently, 304 says your cached copy is still good.

4xx
Client error

The request is the problem: its syntax, its credentials, its permissions, or its target.

5xx
Server error

The server is the problem. Changing your request will not help.

These sixteen codes cover most of what an API returns. Click one to read a plain explanation and a typical case. You do not have to memorize them. Come back and look them up when you meet one.

200 OK

It worked, and the result is in the body.

GET /products/42 returns the product as JSON. This is the most common response in any API.

401 and 403: keep these two apart

401 asks: who are you? The credential is missing, expired, or invalid. A 401 response must include a WWW-Authenticate header telling the client how to authenticate. Send a valid token and the request can succeed. 403 means: I know who you are, and you are not allowed. The identity is clear and the permission is missing, so logging in again changes nothing. The name of 401, Unauthorized, is misleading: it is about authentication, not authorization. That is a historical accident you have to live with.

One more thing: some APIs answer 404 where 403 would be correct, so that you cannot learn that the resource exists. The GitHub API does this. Request a private repository you cannot access and it answers 404, as if the repository did not exist.

§05

Headers: five you will see every day

Headers carry metadata about the message, one Name: value pair per line. There are hundreds of them. These five cover most API work. Some belong on requests, some on responses.

What I am sending
Content-Type

Describes the format of the body in this message. It appears on a request and on a response, whenever there is a body. Send JSON without it and the server may parse the body as a form or as plain text. The usual result is empty fields, or a 400.

Content-Type: application/json; charset=utf-8
What I want back
Accept

A request header. It states which formats the client can handle, and the server picks one. This is called content negotiation. The same resource can be returned as JSON or as another representation.

Accept: application/json
My credential
Authorization

A request header carrying the credential, most often the word Bearer followed by a token. How a token can prove who you are is the subject of chapter 06.

Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
How long it may be stored
Cache-Control

Mostly a response header. It states whether the response may be stored and for how long. The line below means the client may reuse this response for one hour without asking again. A request can send it too, to say what it will accept from a cache.

Cache-Control: max-age=3600
Version identifier
ETag

A response header. It identifies the current version of the resource. Next time the client sends If-None-Match: "33a64df5". If the resource has not changed, the server answers 304 and sends no body.

ETag: "33a64df5"

Two details worth knowing

Header names are case-insensitive. DevTools shows content-type and the documentation writes Content-Type; they are the same header. Header values are a different matter: whether case matters depends on the field. A media type such as application/json is case-insensitive, while an ETag value is not.

Non-standard headers used to be written with an X- prefix, such as X-API-Key. RFC 6648 recommends against that prefix, because such a header often becomes standard later and then the name is wrong. You will still meet X- in plenty of APIs.

§06

One full exchange: request and response side by side

Everything in this chapter, in one round trip. The request you send on the left, the response you get back on the right.

Request · what you send
1GET /v1/products/42 HTTP/1.1
2Host: api.shop.com
3Accept: application/json
GET only reads, so it sends no body and the message ends with the headers. Accept states what the client wants back: JSON.
Response · what comes back
1HTTP/1.1 200 OK
2Content-Type: application/json
3Cache-Control: max-age=60
4ETag: "v7"
5
6{
7 "id": 42,
8 "name": "Mechanical keyboard",
9 "price": 399,
10 "stock": 17
11}
200 means the request succeeded. Cache-Control allows the client to reuse this response for 60 seconds. ETag identifies the version: send it back in If-None-Match later, and an unchanged resource answers 304.

Now send the same kind of request with a different tool. curl is a command line HTTP client. The interface looks nothing like fetch, and the message on the connection is identical:

terminal
1# -i prints the response headers together with the body
2curl -i "https://api.shop.com/v1/products/42"
3
4# A POST: -X sets the method, -H adds a header, -d sends the body
5curl -X POST "https://api.shop.com/v1/products" \
6 -H "Content-Type: application/json" \
7 -d '{ "name": "Mechanical keyboard", "price": 399 }'
The tool changes; the message does not. A browser, fetch, curl, and Postman all produce the same HTTP message. Learn to read the message and you can read any of them. (api.shop.com is an example domain used in this course. The practice tasks below use a real public API.)
§07

Practice

Reading about messages is not the same as looking at one. Three tasks, using DevTools and the browser console.

§08

Quiz

Eight questions on methods, status codes, and headers. Get them all right on the first try to light the chapter dot in the sidebar.

QUESTION 01 / 8

A user posts a new comment. Which HTTP method fits best?

QUESTION 02 / 8

Which of these methods are idempotent — sending the same request many times leaves the server in the same state as sending it once? (Select all that apply.)

QUESTION 03 / 8

Your token is valid and the server knows who you are. You try to delete someone else's article. What should a correct server return?

QUESTION 04 / 8

An API returns 503. What is the most reasonable first reaction?

QUESTION 05 / 8

A request header says Content-Type: application/json. What does it tell the server?

QUESTION 06 / 8

In the URL https://api.shop.com/v1/products/42?sort=price, which part is api.shop.com?

QUESTION 07 / 8

/users/42 currently has three fields: name, email, and bio. You send PUT with only { "name": "New name" }. According to HTTP semantics, what happens?

QUESTION 08 / 8

A client sends a request with a cache validator (If-None-Match plus an ETag). The server finds that the resource has not changed, so it returns only a status code and no body. That status code is ____ (three digits).

What to take away from this chapter
  • One call is one pair of messages. A request is a request line, headers, a blank line, and an optional body. A response has the same four parts, with a status line first.
  • The target says which resource, the method says what to do: GET reads, POST creates, PUT replaces the whole resource, PATCH changes part of it, DELETE removes it.
  • Safe = the request should not change server state. Idempotent = repeating it leaves the same state, which is what makes it safe to retry after a timeout. GET, HEAD, PUT, DELETE, and OPTIONS are idempotent; POST and PATCH are not.
  • The first digit of the status code says whose problem it is: 2xx succeeded, 3xx points elsewhere, 4xx is the request, 5xx is the server. 401 means not authenticated, 403 means not allowed.
  • Five headers cover most of the work: Content-Type (the format I send), Accept (the format I want back), Authorization (my credential), Cache-Control and ETag (caching).