Chapter 02 of 10
Methods and Status Codes
What each HTTP method promises a caller, why PUT and PATCH are not interchangeable, and which status code sets which expectation, with the RFC behind each one.
A method and a status code are the two smallest pieces of an API, and they carry more promises than anything else in the contract. Callers, caches, proxies and retry libraries all act on them without asking you.
What a method promises
HTTP semantics are defined in RFC 9110, and two properties of a method matter for design.
A method is safe when it is essentially read-only, and a client, a crawler or a prefetching browser may therefore call it without being asked twice. A method is idempotent when making the same request more than once has the same effect as making it once, which is what allows a client library to retry automatically after a timeout.
| Method | Safe | Idempotent | Typically used for |
|---|---|---|---|
GET | yes | yes | Reading a resource or a collection |
HEAD | yes | yes | The headers of a GET without the body |
OPTIONS | yes | yes | Communicating supported behaviour |
PUT | no | yes | Replacing a representation in full |
DELETE | no | yes | Removing a resource |
POST | no | no | Creating, submitting and everything else |
PATCH | no | no | Applying a partial modification |
The two properties are the reason retry behaviour is not your decision. A client library that retries a failed PUT is following the specification, so an implementation where a repeated PUT creates a second record is a bug rather than a surprise.
PUT is not a lenient PATCH
The most common semantic mistake in an otherwise careful API is treating PUT as an update that only touches the fields you sent.
PUT replaces the representation, so a field absent from the body is a field the caller is asking you to unset. PATCH, defined separately in RFC 5789, carries a description of changes rather than a new state. Implementing PUT with PATCH semantics works until a caller relies on the specified behaviour to clear an optional field, and then it silently does nothing.
PATCH costs a second decision that teams often skip, which is what the patch document actually looks like. A partial object of the same shape is the common convention and it cannot express removing a field or editing one entry of an array. The formats that can, such as JSON Patch and JSON Merge Patch, are more precise and less pleasant to write by hand. Whichever you pick, the media type has to say which one it is.
Status codes set expectations
A status code is the part of your response that gets read by software you have never seen. Picking a plausible-looking code has consequences beyond documentation.
201 Created says one or more resources came into existence, and it should carry a Location header pointing at the primary one. Clients that follow it avoid parsing your body for an identifier, which is one fewer thing to break.
202 Accepted says the work has not happened yet. It is the correct answer for anything queued, and it obliges you to hand back somewhere to look, usually a status resource the caller can poll. A 202 with nothing to follow leaves the caller with no way to learn the outcome.
204 No Content says the request succeeded and there is deliberately nothing to send. RFC 9110 forbids a body on a 204, and the same applies to 304 Not Modified, so declaring one in your contract makes generated clients emit deserialisation code that will never run.
4xx against 5xx is a statement about blame. A 4xx says the caller can fix this by changing the request, and a 5xx says they cannot. Getting that boundary wrong sends people to the wrong place, because a retry on a genuine 4xx will fail exactly the same way forever.
The codes that need a house rule
A handful of codes are used differently by different APIs, and those are the ones worth deciding once and writing down.
400 against 422 is the usual argument, where 400 covers a request that is malformed and 422 covers one that parses but fails validation. Both are defined in RFC 9110 and both are defensible, so the value is in picking one and using it everywhere rather than in the choice.
404 against 403 is a security decision more than a semantic one. Answering 403 on a resource that exists but is not yours confirms that it exists, and answering 404 does not. That is a deliberate trade of clarity against disclosure, and it should be the same trade on every endpoint.
409 Conflict is worth reserving for the case where the request contradicts the current state, such as a concurrent update or a duplicate that violates a real constraint. Once it starts absorbing general validation failures it stops telling the caller anything.
In Routebase
Methods and responses are edited on the endpoint rather than in a document, and the editor keeps the two consistent with the rest of the specification.

Changing the method on an endpoint only offers methods that are not already taken by another endpoint on the same path, so a collision is prevented rather than reported later. Responses are added one at a time or scaffolded as a set that matches the method, which gives a GET the read codes and a POST the create codes including 409. Common codes arrive with a sensible description already filled in.
Two style guide rules cover the semantics in this chapter. One requires every operation to define at least one success response, and one flags a body declared on a 204 or a 304, citing RFC 9110 and the dead deserialisation code that follows from it. Both ship at Warning, and severities are set per organisation and per project, so a team that wants either as a hard error can raise it. The Responses guide covers the editor, and the Style Guide covers the rules and their severities.
Frequently asked questions
What is the difference between PUT and PATCH?
PUT replaces the whole representation of a resource, so anything you leave out of the body is meant to be removed. PATCH applies a partial modification described by the request body, which is defined in RFC 5789 rather than in the core HTTP semantics. The practical consequence is that PUT is idempotent and a PATCH generally is not, because a patch that increments a value produces a different result each time it is applied.
Which HTTP methods are idempotent?
RFC 9110 defines PUT and DELETE as idempotent, along with the safe methods GET, HEAD, OPTIONS and TRACE. POST and PATCH are not idempotent by definition, which is why a create that must not run twice needs an idempotency key rather than a well chosen verb. Idempotent means that repeating the request has the same effect as making it once, and it does not mean the response has to be identical.
When should an API return 201 versus 200?
Return 201 Created when the request resulted in one or more new resources, and include a Location header pointing at the primary one. Return 200 when the request succeeded without creating anything, such as a read or an update in place. The distinction matters to callers that follow the Location header rather than parsing the body for an identifier.
What does HTTP 202 Accepted mean?
202 says the request was accepted for processing and that the processing has not finished, so the response body cannot contain the result. It is the honest code for work that runs asynchronously, and it obliges you to give the caller somewhere to look for the outcome. In practice that means returning a reference to a status resource the caller can poll, because a 202 with no follow-up leaves the caller guessing.
Last reviewed by The Routebase Team.