Status codes, class by class
The five classes, the success and redirect codes an API actually uses, and why 307 and 308 exist when 301 and 302 already did.
After this lesson you can
- Explain how a client must treat a status code it does not recognise
- Choose between 200, 201, 202 and 204 for a successful request
- Say which redirect codes keep the method and body, and which may turn a POST into a GET
A status code is a three-digit number whose first digit is its
class. The class is the part every client is required to understand:
RFC 9110 says a client that receives a code it does not recognise must
treat it as the x00 code of the same class. A client that has never
heard of 451 still knows it is a client error and handles it like 400.
| Class | Meaning |
|---|---|
| 1xx | Informational — interim, the final response is still coming |
| 2xx | Successful — the request was received, understood and accepted |
| 3xx | Redirection — the client must do something more to finish |
| 4xx | Client error — the request is malformed or cannot be fulfilled as sent |
| 5xx | Server error — the request may be fine; the server failed |
const KNOWN = { 200: "OK", 201: "Created", 400: "Bad Request", 404: "Not Found", 500: "Internal Server Error" };const CLASS = { 1: "informational", 2: "success", 3: "redirection", 4: "client error", 5: "server error" }; function interpret(code) { const cls = Math.floor(code / 100); if (KNOWN[code]) return `${code}: ${KNOWN[code]}`; const fallback = cls * 100; return `${code}: unknown, handle as ${fallback} (${CLASS[cls]})`;} export function run() { return [201, 299, 451, 404, 599].map(interpret);}That rule is why inventing private codes is pointless: nobody else's client will know them, and they will be read as their class anyway.
The success codes an API uses
- 200 OK — the default success, with a body that depends on the method: the resource for GET, a result for POST, the updated resource for PUT or PATCH if you choose to return it.
- 201 Created — a new resource exists. Send a
Locationheader with its URI; without one, the created resource is taken to be the request's own target URI. - 202 Accepted — the request was accepted for processing that has
not finished, and may still fail. The body should tell the client
where to check on it, typically a status resource such as
/jobs/91. - 204 No Content — success with no body at all. Common for DELETE, and for PUT or PATCH when the client already knows the new state.
HTTP/1.1 201 Created
Location: /orders/1042
Content-Type: application/json
{"id": "1042", "status": "pending"}
Redirects: what happens to the method
Redirects carry a Location, and the question that matters for an API
is what the client does with the method and body when it follows one.
- 301 Moved Permanently and 302 Found — for historical reasons, RFC 9110 allows a user agent to change a POST into a GET when it follows them, and browsers do. Other methods are kept.
- 303 See Other — "go GET that other resource": the client follows with GET (or HEAD for a HEAD request), whatever the original method. The classic use is after a POST, pointing at the result.
- 307 Temporary Redirect and — the client must repeat the request with the . These exist precisely because 301 and 302 could not guarantee that.
// How a browser-like client follows a redirect.function follow(status, method) { if ([301, 302].includes(status)) return method === "POST" ? "GET, body dropped" : `${method}, unchanged`; if (status === 303) return method === "HEAD" ? "HEAD" : "GET, body dropped"; if ([307, 308].includes(status)) return `${method}, same body`; return "not a redirect to follow";} export function run() { const out = {}; for (const status of [301, 302, 303, 307, 308, 304]) { out[status] = { POST: follow(status, "POST"), PUT: follow(status, "PUT") }; } return out;}4xx against 5xx
The split is about blame and about retrying. A 4xx says the client must change something — or, for a few codes such as 408 and 429, wait before trying again; a 5xx says the server failed and the same request might succeed later. Returning 500 for a validation failure makes clients retry a request that can never work, and returning 400 for a database outage tells them to stop sending a request that was fine. The next lesson goes through the 4xx codes one by one.
Common mistakes
- Returning
200 OKwith{"error": "..."}in the body. Every client, proxy and monitoring tool now records a success. - A 201 with no
Locationheader, so the client has to guess or parse the body to find the new resource. - A 204 that carries a body: by definition it has none, and clients will not read it.
- Redirecting a POST endpoint with 301 or 302 and losing the body when the client switches to GET; use 307 or 308.
What interviewers ask
- What is the difference between 200, 201, 202 and 204? — 201 means a
resource was created (with
Location), 202 means accepted but not finished, 204 means success with no body, 200 is the general case. - Why do 307 and 308 exist? — they guarantee the method and body are preserved; 301/302 let user agents switch POST to GET.
- Your API returns 500 for invalid input. Why does that matter? — 5xx blames the server and invites retries; invalid input is a 4xx, so the client knows to fix the request.
Exercise · Pro
The right success response
Exercises are free in the first 3 lessons of every course. From here on they are part of Pro and Sprint; the lesson and its runnable examples stay open.
Upgrade