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.
On this page
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.
| Method | Typical use | Safe | Idempotent | Cacheable |
|---|---|---|---|---|
GET | Read a resource | Yes | Yes | Yes |
HEAD | Like GET, but headers only | Yes | Yes | Yes |
OPTIONS | Ask what is allowed (CORS preflight) | Yes | Yes | No |
PUT | Replace a resource with the body | No | Yes | No |
DELETE | Remove a resource | No | Yes | No |
POST | Create something, or run an action | No | No | Rarely |
PATCH | Change part of a resource | No | Not guaranteed | No |
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:
- The client makes a unique key and sends it in a header.
- The server saves the result of the first request.
- If the same key comes again, the server returns the saved result and does not do the work twice.
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
addandremove) 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/42means "make the resource at this URL look like this." The client chooses the ID. You can repeat it safely.POST /usersmeans "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.
| Family | Meaning | Examples you must know |
|---|---|---|
| 1xx | Information | 101 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) |
| 2xx | Success | 200 OK, 201 Created (+ Location), 202 Accepted, 204 No Content |
| 3xx | Redirection | 301, 302, 303, 304, 307, 308 |
| 4xx | The client made a mistake | 400, 401, 403, 404, 405, 409, 410, 412, 415, 422, 429 |
| 5xx | The server failed | 500, 502, 503, 504 |
Success codes
200 OK: the request worked and there is a body.201 Created: a resource was created. Include aLocationheader 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 forDELETEand somePUTrequests.
Client errors that get confused
| Code | Use when | Notes |
|---|---|---|
400 Bad Request | The request is broken (invalid JSON, missing required parameter) | Generic. Use a more specific code if one fits |
401 Unauthorized | The user is not logged in: no credentials, or wrong ones | The 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 Forbidden | The user is logged in, but not allowed | Logging in again will not help |
404 Not Found | The resource does not exist | Also used to hide that a resource exists, so users cannot guess other people's IDs |
405 Method Not Allowed | The URL exists, but not for this method | Send an Allow header |
409 Conflict | The request clashes with the current state (duplicate unique value, edit conflict) | Common when two people edit the same record |
410 Gone | It existed and was removed for good | Stronger than 404 for SEO |
412 Precondition Failed | An If-Match or If-Unmodified-Since condition failed | The 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 Type | You sent a Content-Type the server cannot handle | |
422 Unprocessable Content | The 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 Requests | The rate limit (the maximum number of requests allowed in a time window) was reached | Include 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 sendRetry-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:
- Is it permanent?
- Must the method and body stay the same?
| Code | Permanent? | Method on the next request | Cached by default? |
|---|---|---|---|
301 Moved Permanently | Yes | May change POST to GET (old behaviour) | Yes |
302 Found | No (temporary) | May change POST to GET (old behaviour) | No (needs explicit freshness) |
303 See Other | No | Always becomes GET | No |
307 Temporary Redirect | No | Kept (a POST stays a POST with the same body) | No |
308 Permanent Redirect | Yes | Kept | Yes |
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(or308). - A temporary redirect (A/B test, maintenance): use
302or307. - After a form
POST, send the user to a result page: use303. This is the Post/Redirect/Get pattern: the server answers aPOSTwith a redirect, and the browser then loads the result page withGET. It stops a page refresh from sending the form again. - A
POSTendpoint has moved and clients must send the body again: use307(temporary) or308(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-LanguageandAccept-Encodingto ask for a type, language or format. The server answers withContent-TypeandContent-Language.406means "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-Matchis for caching and can give304.If-Matchis for safe updates and can give412. - Range requests: ask for only part of a file.
Range: bytes=0-1023returns206 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,statusanddetail.
Common mistakes
- Sending
200 OKwith{ "error": ... }in the body. Clients, monitors and caches rely on status codes. Use the right 4xx or 5xx code. - Using
401to mean "forbidden." Use403. - Creating resources with
GET, or deleting with a link that a prefetcher can follow. - Treating
POSTas idempotent, then retrying payments blindly. - Returning
500for client mistakes such as bad input. - Using a permanent redirect (
301) to test something. You then cannot undo it in your users' browsers. - Redirecting
POSTwith301or302and 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.
307and308keep the method.303forcesGET. - 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
- HTTP Methods, Status Codes and Idempotency in Practice · API Design
- REST API Design Best Practices: Resources, Versioning, Status Codes · Backend in Depth
- What Makes a Good API: Resources, URLs and the Contract · API Design
Related series