Medium system-design api

Which HTTP methods are safe or idempotent, and how do status codes and caching fit?

The 30 second answer

Safety means the method is essentially read-only. RFC 9110 defines GET, HEAD, OPTIONS and TRACE as safe. Idempotency means repeating the same request has the same intended effect as doing it once; PUT, DELETE and all safe methods are idempotent, and POST is not. PATCH, defined separately, is neither safe nor idempotent as specified. I would only retry automatically when the method is idempotent, and I would cache only when the response says I may.

HTTP vests request semantics in the method, not in the URI. RFC 9110 defines two properties that interviewers use constantly.

Safe methods have essentially read-only semantics: they should not have the significance of taking an action other than retrieval. RFC 9110 defines GET, HEAD, OPTIONS and TRACE as safe.

Idempotent methods have the same intended effect on the server whether they are issued once or several times with identical requests. RFC 9110 defines PUT, DELETE, and all safe methods as idempotent. POST is neither safe nor idempotent. Automatic retries after a connection failure are allowed for idempotent methods under the conditions in Section 9.2.2.

PATCH is defined separately in RFC 5789. It applies a partial modification described by a patch document. PATCH is neither safe nor idempotent as specified, although a particular patch media type can be designed to be idempotent.

A compact map, following RFC 9110 (and RFC 5789 for PATCH):

MethodTypical useSafeIdempotent
GETRetrieve a representationYesYes
HEADSame as GET, headers onlyYesYes
OPTIONSDescribe communication optionsYesYes
PUTReplace the target resource with the enclosed representationNoYes
DELETERemove the target resourceNoYes
POSTProcess the enclosed representation according to the resource's own semantics, often create or perform an actionNoNo
PATCHApply a partial modificationNoNo, as specified

Zalando's guidelines require teams to use these HTTP methods with their standardized semantics and, as a should-rule, to consider making POST and PATCH idempotent in design (for example with a secondary key or an Idempotency-Key header) even though the HTTP specifications do not require it.

A response includes a three-digit status code (RFC 9110, Section 15). The classes are 1xx informational, 2xx successful (200, 201, 204), 3xx redirection (304), 4xx client error (400, 401, 403, 404, 409, 429) and 5xx server error (500, 503). Zalando requires official status codes used with their intended semantics, the most specific applicable code, and Problem JSON (application/problem+json) for error bodies. APIs must not expose stack traces.

Caching is a first-class REST constraint and a first-class part of HTTP. RFC 9110 points to RFC 9111 for cache behaviour. Freshness is controlled by fields such as Cache-Control and Expires, validators such as ETag and Last-Modified, and conditional requests (If-None-Match, If-Modified-Since). GET and HEAD are the usual cache targets. Other methods are not cacheable by default; a POST response can be stored only when explicit freshness information is present, as specified in RFC 9111. Intermediaries can only reuse a response when the message itself says that this is allowed.

Example: a cacheable GET and a Problem JSON error.

GET /product-offers?q=navy%20sneakers&limit=2 HTTP/1.1
Host: catalog.example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, max-age=30
ETag: "p-offers-77"

{
  "items": [
    {
      "id": "p-1001",
      "title": "Navy sneakers",
      "price": {"amount": 79.95, "currency": "EUR"}
    }
  ]
}
HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "https://api.example.com/problems/not-found",
  "title": "Product offer not found",
  "status": 404,
  "detail": "No product offer with id p-9999."
}

Alternate interview scenarios

"A client retried a POST after a timeout and created two orders. What went wrong?"

POST is not idempotent by default, so a second identical request may create a second resource. I would make that particular POST idempotent in design, for example with a client-supplied idempotency key or a secondary business key, and return the original order on a replay. I would not claim that HTTP itself makes POST safe to retry.

"Can I retry a PUT or a DELETE after a connection drop?"

Yes, in the sense that RFC 9110 defines those methods as idempotent: the intended effect of several identical requests is the same as one. I still need the server to implement that contract, and I would use validators such as ETag and If-Match if concurrent updates are a risk.

Sources (8)
  1. RFC 9110, Safe methodsrfc-editor.org
  2. RFC 9110, Idempotent methodsrfc-editor.org
  3. RFC 5789, PATCH Method for HTTPrfc-editor.org
  4. Zalando RESTful API Guidelines, HTTP requestsopensource.zalando.com
  5. RFC 9110, Status codesrfc-editor.org
  6. Zalando RESTful API Guidelines, HTTP status codes and errorsopensource.zalando.com
  7. RFC 9110, Cachesrfc-editor.org
  8. RFC 9111, HTTP Cachingrfc-editor.org