In an HTTP API contract, what is the difference between a method being safe and being idempotent, and which of GET, POST, PUT, PATCH and DELETE are which?
answer
- safe = read-only (GET, HEAD, OPTIONS)
- idempotent = same state after N calls (GET, HEAD, PUT, DELETE)
- safe implies idempotent, never the reverse
- POST and PATCH: neither by default
- state, not status code: DELETE gives 204 then 404 and is still idempotent
basics
~20 sSafe means the request does not change server state - GET and HEAD. Idempotent means doing it N times leaves the same state as doing it once - GET, HEAD, PUT and DELETE. POST and PATCH are neither by default. Safe implies idempotent.
solid answer
~50 sTwo separate promises the API makes about a method. - **Safe**: the request is read-only; it must not modify server state. GET, HEAD and OPTIONS. Anything safe is automatically idempotent, since it changes nothing. - **Idempotent**: applying the request once or many times leaves the resource in the same state. GET, HEAD, PUT and DELETE. - **Neither by default**: POST and PATCH. `POST /orders` twice creates two orders; a PATCH body like `{"op":"increment","amount":1}` applies twice. Two clarifications interviewers look for. First, idempotency is about **resulting state, not the response**: `DELETE /orders/42` returns 204 then 404, but the state - order gone - is identical, so it is still idempotent. Second, these are **contract promises, not enforcement**. HTTP cannot stop you writing a GET handler that charges a card; it just means every cache, crawler and retry layer will now do the wrong thing, because they all trust the declaration.
code
http · 7 linesDELETE /orders/42 HTTP/1.1
HTTP/1.1 204 No Content
DELETE /orders/42 HTTP/1.1
HTTP/1.1 404 Not Foundgo deeper
Give the two definitions crisply and classify the five methods correctly; that alone is a pass.
Add that idempotency is about resulting state rather than response status, and explain why PUT's full-representation semantics make it repeatable.
Emphasise that these are declarations infrastructure acts on - caches, prefetchers, retrying proxies - so violating them is an operational hazard, not a style issue.
Position them as the contract that lets generic intermediaries and client retry policies exist at all, and discuss what breaks system-wide when a handler lies about its method's properties.
## Two distinct promises **Safe** means the method is essentially read-only: issuing the request should not change observable server state. GET, HEAD and OPTIONS are safe. "Essentially" allows harmless byproducts - access logs, hit counters, cache warming - because the *client* is not asking for a change. **Idempotent** means the effect on server state of N identical requests (N greater than or equal to 1) is the same as that of one request. GET, HEAD, OPTIONS, PUT and DELETE are idempotent. POST and PATCH are not, by definition of the method. Safe implies idempotent: a request that changes nothing trivially leaves the same state however many times you send it. The reverse does not hold - DELETE is idempotent but very much not safe. ## Method by method **GET / HEAD** - safe and idempotent. Read the resource; HEAD returns headers only. **PUT** - idempotent, not safe. PUT carries the complete intended representation: "make the resource at this URL look like this". Sending it five times leaves the resource in exactly the state the body describes. The result does not depend on the prior state, which is precisely why repetition is harmless. **DELETE** - idempotent, not safe. After the first successful delete the resource is gone; further deletes cannot remove it more thoroughly. The end state - absent - is stable. **POST** - neither. POST means "process this payload according to the resource's own semantics", and the usual semantics is to create something new or run an action. `POST /orders` twice yields two orders. That is not a flaw; it is what the method promises. **PATCH** - not idempotent in general. It carries a *modification*, and whether repeating a modification is harmless depends entirely on the patch. `{"status":"SHIPPED"}` happens to be repeatable; `{"op":"increment","path":"/qty","value":1}` is not. Because it is not guaranteed, the specification declines to declare PATCH idempotent, and infrastructure must assume it is not. ## The definition is about state, not the response The most common misunderstanding. `DELETE /orders/42` returns 204 the first time and 404 the second. Different status codes - identical resulting state. The method is idempotent. Likewise a PUT may return 201 on first call and 200 afterwards. Idempotency constrains the **effect**, never the response body or status. ## They are promises, not enforcement Nothing in HTTP prevents you writing `GET /orders/42/cancel` that cancels an order. The protocol will not stop you - but the entire ecosystem is built on trusting the declaration: - **Caches** may store and replay GET responses without contacting your server. - **Crawlers, prefetchers and link scanners** follow GET links freely; the historic case of a web accelerator following GET-based "delete" links and wiping a CMS is the standard cautionary tale. - **Proxies, load balancers and HTTP client libraries** retry idempotent methods automatically on connection failures and timeouts. So a state-changing GET is not a style violation - it is a live production hazard, because generic infrastructure will exercise it. ## How to say it in an interview Give both definitions in one sentence each, list which methods fall where, then volunteer the two clarifications: idempotency is about resulting state rather than the response, and these are contractual declarations that infrastructure trusts rather than behaviours the protocol enforces. That last point is what separates a recited answer from an understood one.
- Is PATCH idempotent?Not in general, so infrastructure must assume it is not. A PATCH body that sets an absolute value, such as `{"status":"SHIPPED"}`, happens to be repeatable, but one expressing a relative change, such as incrementing a quantity, is not. Because the guarantee depends on the payload rather than the method, HTTP does not declare PATCH idempotent.
- What is wrong with a GET endpoint that deletes a resource, given it works when you test it?Every generic HTTP participant assumes GET is safe. Shared caches may serve and replay it, prefetchers and crawlers will follow the link unprompted, and clients or proxies retry it on failure. The endpoint will be triggered without any user intent, which is how link-prefetching agents have historically wiped data through GET-based delete links.
saying these in an interview costs you the question
- Saying idempotent means 'returns the same response every time' rather than leaves the same state
- Claiming DELETE is not idempotent because the second call returns 404
- Calling GET idempotent but not safe, or confusing the two terms
- Asserting PATCH is idempotent because a particular PATCH body happens to be repeatable
- Believing HTTP enforces these properties rather than the handler having to honour them