The Browser Contract

HTTP Semantics Interviewers Ask: Methods, Idempotency, Status Codes, Redirects

Safe vs idempotent methods, 401 vs 403, 409, 422 and 429, and the 301/302/307/308 table. All based on the HTTP specification.

Lesson 0615 min read#http#rest#status-codes

On this page

  1. Methods: safe, idempotent, cacheable
  2. Status codes by family
  3. Redirects: the 301 / 302 / 303 / 307 / 308 table
  4. Other HTTP details worth a sentence
  5. Common mistakes
  6. Interview questions
  7. Key takeaways
  8. What's next

In one line: the HTTP method says what you want to do. The status code says what happened. The redirect code says where to go next and whether to keep the method. Interviewers use these to see if you design APIs on purpose or by habit.

An HTTP method (also called a verb) is a word at the start of a request, such as GET or POST, that names the action you want. A status code is a three-digit number at the start of a response, such as 404, that tells the client the result. A header is a line of "name: value" extra information sent with a request or response. This is vocabulary, but it has real effects. Retries, caching, redirects and error handling in the frontend all depend on it. In this lesson you learn three things: the three properties of methods, the status-code families, and the redirect table.

Methods: safe, idempotent, cacheable

Three properties describe how a method behaves:

  • Safe: it does not change anything on the server. It is read-only in intent. A crawler (a program that visits many pages, like a search engine bot) and a prefetcher (a tool that loads pages ahead of time) may call safe methods freely.
  • Idempotent (say "eye-dem-POH-tent"): doing it once or many times gives the same result on the server. Think of a light switch marked "ON". Pressing it five times leaves the light on, the same as pressing it once. This means it is safe to retry after a timeout.
  • Cacheable: the browser or a proxy (a server that passes requests on for someone else) may store the response and reuse it (Lesson 05).

Difference in one line: safe means "does not change anything"; idempotent means "repeating it changes nothing more". A safe method is always idempotent, but DELETE is idempotent and not safe.

MethodTypical useSafeIdempotentCacheable
GETRead a resourceYesYesYes
HEADLike GET, but headers onlyYesYesYes
OPTIONSAsk what is allowed (CORS preflight)YesYesNo
PUTReplace a resource with the bodyNoYesNo
DELETERemove a resourceNoYesNo
POSTCreate something, or run an actionNoNoRarely
PATCHChange part of a resourceNoNot guaranteedNo

What "idempotent" really means

It is about the effect on the server, not about the response. Take DELETE /orders/7. It returns 204 the first time and 404 the second time. But the end state is the same: order 7 does not exist. So it is idempotent. Another example: PUT /users/5 with the same full body five times leaves the same user.

POST /orders is different. It creates a new order every time. If you retry after a timeout, you can create a duplicate order.

That is why payment and order endpoints use an idempotency key. An idempotency key is a unique ID the client sends with a request, so the server can recognise a repeat and not do the work twice. It works like this:

  1. The client makes a unique key and sends it in a header.
  2. The server saves the result of the first request.
  3. If the same key comes again, the server returns the saved result and does not do the work twice.
HTTP
POST /payments HTTP/2Idempotency-Key: 3d1c0b6e-6a9e-4c4e-9f0a-1a2b3c4d5e6fContent-Type: application/json{ "amount": 4999, "currency": "INR" }

Is PATCH idempotent?

Not by definition. It depends on what the patch says.

  • PATCH { "views": 10 } sets a value (this style is called JSON Merge Patch: you send the fields you want to change). Doing it twice gives the same result, so it is idempotent.
  • PATCH { "op": "increment" } adds one each time, so it is not idempotent.
  • A JSON Patch (a list of step-by-step operations such as add and remove) that adds an item to an array is also not idempotent.

A good answer is: "It depends on the patch. I design it to be idempotent when I can, or I use an idempotency key."

PUT vs POST for creating

  • PUT /users/42 means "make the resource at this URL look like this." The client chooses the ID. You can repeat it safely.
  • POST /users means "create a new user." The server chooses the ID. You cannot repeat it safely without a key.

Status codes by family

The first digit tells you the family.

FamilyMeaningExamples you must know
1xxInformation101 Switching Protocols (used to upgrade to WebSocket, a long-lived two-way connection), 103 Early Hints (a first hint to the browser about files to load while the real response is still being made)
2xxSuccess200 OK, 201 Created (+ Location), 202 Accepted, 204 No Content
3xxRedirection301, 302, 303, 304, 307, 308
4xxThe client made a mistake400, 401, 403, 404, 405, 409, 410, 412, 415, 422, 429
5xxThe server failed500, 502, 503, 504

Success codes

  • 200 OK: the request worked and there is a body.
  • 201 Created: a resource was created. Include a Location header with its URL.
  • 202 Accepted: the work is queued, not finished. Examples are a video conversion or a report. Return a status URL that the client can check again and again (this is called polling: asking repeatedly "are you done yet?").
  • 204 No Content: success with no body. This is typical for DELETE and some PUT requests.

Client errors that get confused

CodeUse whenNotes
400 Bad RequestThe request is broken (invalid JSON, missing required parameter)Generic. Use a more specific code if one fits
401 UnauthorizedThe user is not logged in: no credentials, or wrong onesThe name is misleading (it is really about authentication, not authorization). Send a WWW-Authenticate header, which tells the client how to log in. The fix is to log in
403 ForbiddenThe user is logged in, but not allowedLogging in again will not help
404 Not FoundThe resource does not existAlso used to hide that a resource exists, so users cannot guess other people's IDs
405 Method Not AllowedThe URL exists, but not for this methodSend an Allow header
409 ConflictThe request clashes with the current state (duplicate unique value, edit conflict)Common when two people edit the same record
410 GoneIt existed and was removed for goodStronger than 404 for SEO
412 Precondition FailedAn If-Match or If-Unmodified-Since condition failedThe standard way to do optimistic locking: you do not lock the data, you only check at save time that nobody changed it since you read it. It often uses an ETag, a fingerprint (version label) of the content
415 Unsupported Media TypeYou sent a Content-Type the server cannot handle
422 Unprocessable ContentThe request is well formed, but the meaning is wrong (an email without @, a negative quantity)Often used for validation errors. Some APIs use 400 instead. Be consistent
429 Too Many RequestsThe rate limit (the maximum number of requests allowed in a time window) was reachedInclude Retry-After

401 vs 403 in one line (authentication vs authorization): authentication is proving who you are, and authorization is deciding what you may do. 401 means "I don't know who you are." 403 means "I know who you are, and the answer is no."

Server errors

  • 500 Internal Server Error: an unexpected bug.
  • 502 Bad Gateway: a proxy or gateway (a server in front of your app that forwards requests) got a bad response from the server behind it (the upstream server).
  • 503 Service Unavailable: the server is overloaded or in maintenance. It can send Retry-After.
  • 504 Gateway Timeout: the proxy waited too long for the upstream server.

A client may retry 502, 503, 504 and 429 for idempotent requests. It should wait a little longer before each retry (this is called backoff). Do not blindly retry 400 or 422. The same request will fail again.

Redirects: the 301 / 302 / 303 / 307 / 308 table

A redirect tells the browser: "go to another URL." Two questions describe every redirect:

  1. Is it permanent?
  2. Must the method and body stay the same?
CodePermanent?Method on the next requestCached by default?
301 Moved PermanentlyYesMay change POST to GET (old behaviour)Yes
302 FoundNo (temporary)May change POST to GET (old behaviour)No (needs explicit freshness)
303 See OtherNoAlways becomes GETNo
307 Temporary RedirectNoKept (a POST stays a POST with the same body)No
308 Permanent RedirectYesKeptYes

Why do 307 and 308 exist? Early browsers changed a POST into a GET on 301 and 302 redirects. Later, the specification accepted this habit. Then 307 and 308 were added, so there is a clear code for "temporary or permanent, and keep the method."

Rules of thumb:

  • A page (GET) has a new permanent URL, for SEO (search engine optimization, getting a good place in search results): use 301 (or 308).
  • A temporary redirect (A/B test, maintenance): use 302 or 307.
  • After a form POST, send the user to a result page: use 303. This is the Post/Redirect/Get pattern: the server answers a POST with a redirect, and the browser then loads the result page with GET. It stops a page refresh from sending the form again.
  • A POST endpoint has moved and clients must send the body again: use 307 (temporary) or 308 (permanent).

301 and 308 are cached for a long time. After a browser saves a permanent redirect, it can keep following it without asking your server. This can continue even after you remove the redirect. If you are not sure it is permanent, use 302 or 307 first. This is also why URL shorteners that need click analytics often choose a temporary redirect (Practical Design Problems, Lesson 01).

Other HTTP details worth a sentence

  • Content negotiation: the client and server agree on a format. The client uses Accept, Accept-Language and Accept-Encoding to ask for a type, language or format. The server answers with Content-Type and Content-Language. 406 means "I can't make what you asked for."
  • Conditional requests: requests that only act if a condition about the stored version is true. If-None-Match is for caching and can give 304. If-Match is for safe updates and can give 412.
  • Range requests: ask for only part of a file. Range: bytes=0-1023 returns 206 Partial Content. This is how video seeking and resumable downloads work.
  • Errors: return a body in a steady format that a program can read. A common standard is "problem details" (RFC 9457), a JSON error format with the fields type, title, status and detail.

Common mistakes

  1. Sending 200 OK with { "error": ... } in the body. Clients, monitors and caches rely on status codes. Use the right 4xx or 5xx code.
  2. Using 401 to mean "forbidden." Use 403.
  3. Creating resources with GET, or deleting with a link that a prefetcher can follow.
  4. Treating POST as idempotent, then retrying payments blindly.
  5. Returning 500 for client mistakes such as bad input.
  6. Using a permanent redirect (301) to test something. You then cannot undo it in your users' browsers.
  7. Redirecting POST with 301 or 302 and losing the body.

Interview questions

Is PUT idempotent? Is PATCH?

PUT is idempotent by definition. If you send the same full replacement many times, the state stays the same. PATCH is not guaranteed to be idempotent. It depends on the operation. Setting a field to a value is idempotent. "Increment" or "append" is not. To make non-idempotent operations safe to retry, use an idempotency key.

401 vs 403?

401 means the request has no valid login. The client should log in, and the response should say how, using WWW-Authenticate. 403 means the client is logged in but is not allowed to do this. Logging in again will not change a 403.

Why do 307/308 exist when 301/302 already did?

Browsers used to change POST to GET on 301 and 302. So there was no code for "redirect and keep the method and body." 307 (temporary) and 308 (permanent) promise that the method stays the same.

Scenario: a POST endpoint has moved. Which redirect keeps the request body?

Use 308 if the move is permanent. Use 307 if it is temporary. 301 and 302 may change the request to GET and drop the body. If a form submission should end on a results page, use 303 instead.

When should you return 202?

Use it when the server accepted the request but the work is not finished. Examples are report generation, video processing and bulk imports. Return 202 with a Location that points to a status resource, or with a job ID. The client can check it again and again, or you can tell the client through a webhook (a URL on the client's side that the server calls when the job is done).

What is the difference between 400 and 422?

400 means the request is broken, for example bad JSON, a missing parameter or a wrong type. 422 means the server understood the request and the format is fine, but it breaks a business or validation rule. Many APIs use 400 for everything. What matters is that you write it down and stay consistent.

What is "safe" vs "idempotent"?

Safe methods do not change server state. GET, HEAD and OPTIONS are safe, so a tool can prefetch them and call them freely. Idempotent methods may change state, but repeating them has no extra effect. PUT and DELETE are idempotent, so you can retry them. Every safe method is idempotent. But not every idempotent method is safe.

What does 304 mean and what must the server do?

304 Not Modified is the answer to a conditional request (If-None-Match or If-Modified-Since). It means the copy the client already has is still good. The server sends no body. It should repeat the useful headers such as ETag and Cache-Control.

Scenario: a client gets 409 Conflict when saving an edit. How should the API and the UI behave?

A 409 (or 412 when If-Match fails) means the record changed after the client read it. The API should return the current version and a stable error code. The UI should not silently overwrite the data. It should reload the latest data, show what changed, and let the user merge the changes or try again. ETags or a version column make this check cheap and reliable.

Key takeaways

  • Safe means no state change. Idempotent means you can repeat it with no extra effect. Know the table by heart.
  • Let the status code carry the result: 401 = log in, 403 = not allowed, 409 = state conflict, 422 = validation, 429 = slow down.
  • Redirects are a 2×2 table: permanent or temporary × method kept or not. 307 and 308 keep the method. 303 forces GET.
  • Make retries safe with idempotency keys and by choosing methods carefully.

What's next

Lesson 07: Frontend Security Checklist. Now the transport rules are clear. Next we look at the page itself: XSS sinks, Content Security Policy, clickjacking and the supply chain.

Published by Jainik · Last updated · How these lessons are made

Keep learning

Related lessons

Related series