This cheatsheet compares the nine HTTP request methods by what they promise, whether a retry is safe, whether they carry a body and whether a cache may store the answer. It is for developers designing a REST API or debugging a 405 response. The confusion it clears up is the difference between safe and idempotent, and why PUT and PATCH are not interchangeable. See the HTTP, REST and Idempotent glossary pages for the concepts.
| Method | Safe | Idempotent | Request body | Cacheable response | Typical success code |
|---|---|---|---|---|---|
| GET | Yes | Yes | No defined meaning | Yes | 200 |
| HEAD | Yes | Yes | No defined meaning | Yes | 200, no body |
| POST | No | No | Yes | Only with explicit freshness information | 201 or 200 |
| PUT | No | Yes | Yes | No | 201 if created, 200 or 204 if replaced |
| PATCH | No | No, unless you design it so | Yes, a patch document | Only with explicit freshness information | 200 or 204 |
| DELETE | No | Yes | No defined meaning | No | 200, 202 or 204 |
| OPTIONS | Yes | Yes | Optional | No | 200 or 204 |
| CONNECT | No | No | Not used | No | 200, then a tunnel |
| TRACE | Yes | Yes | Must not be sent | No | 200 |
Safe, idempotent and cacheable come from RFC 9110 sections 9.2 and 9.3. PATCH is defined separately in RFC 5789.
| Method | What it asks the server to do |
|---|---|
| GET | Send a current representation of the target resource |
| HEAD | Same as GET but send headers only |
| POST | Process the enclosed data by the resource's own rules, such as creating a child resource |
| PUT | Replace the target resource's state with the enclosed representation |
| PATCH | Apply a partial change described by the enclosed patch document |
| DELETE | Remove the association between the target resource and its functionality |
| OPTIONS | Describe the communication options for the resource, or `*` for the whole server |
| CONNECT | Open a tunnel to the host and port in the request target |
| TRACE | Echo the request back as a loop-back test |
| Term | Definition | Methods |
|---|---|---|
| Safe | The client expects no state change | GET, HEAD, OPTIONS, TRACE |
| Idempotent | Repeating the request has the same intended effect as sending it once | GET, HEAD, OPTIONS, TRACE, PUT, DELETE |
Every safe method is idempotent. PUT and DELETE are idempotent but not safe.
| Situation | Status | Header to send |
|---|---|---|
| Method known but not allowed for this resource | 405 Method Not Allowed | `Allow` listing the allowed methods |
| Method unknown or not implemented by the server | 501 Not Implemented | None required |
| PATCH body in a format the server cannot apply | 415 Unsupported Media Type | `Accept-Patch` |
$ curl -X POST -d {"name":"a"} /items
HTTP/1.1 201 Created
Location: /items/1
$ curl -X PUT -d {"name":"b"} /items/7
HTTP/1.1 201 Created
$ curl -X PUT -d {"name":"b"} /items/7
HTTP/1.1 204 No Content
$ curl -X PATCH -d {"qty":2} /items/7
HTTP/1.1 200 OK
Content-Type: application/json
{"name":"b","qty":2}
$ curl -X DELETE /items/7
HTTP/1.1 204 No Content
This is real output from a small Node server. POST returns 201 with a Location header because the server picks the new URL. PUT to a URL the client chose returns 201 the first time and 204 on the repeat.
$ curl -X POST -d {"name":"a"} /items
HTTP/1.1 201 Created
Location: /items/1
$ curl -X POST -d {"name":"a"} /items
HTTP/1.1 201 Created
Location: /items/2
Sending the same POST twice created two items, /items/1 and /items/2. Repeating the PUT above left one item at /items/7 both times. That is why a client may retry a PUT after a dropped connection but should not blindly retry a POST.
$ curl -X OPTIONS /items
HTTP/1.1 204 No Content
Allow: GET, HEAD, POST, OPTIONS
$ curl -X DELETE /items
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, POST, OPTIONS
$ curl -I /items
HTTP/1.1 200 OK
Content-Type: application/json
OPTIONS answers with an Allow header, and a disallowed method gets 405 with the same header. curl -I sends HEAD, which returns headers only.
$ curl -X DELETE /items/7
HTTP/1.1 204 No Content
$ curl -X DELETE /items/7
HTTP/1.1 404 Not Found
The status code differs on the repeat, but the server state is the same, so DELETE is still idempotent. Idempotent describes the effect on the server, not the response.
const mk = m => new Request('http://localhost:8099/items/7', { method: m }).method;
console.log(mk('patch'), mk('put'), mk('PATCH'));
try { new Request('http://localhost:8099/', { method: 'TRACE' }); }
catch (e) { console.log(e.name + ': ' + e.message); }
try { new Request('http://localhost:8099/', { method: 'GET', body: 'x' }); }
catch (e) { console.log(e.name + ': ' + e.message); }
patch PUT PATCH
TypeError: 'TRACE' HTTP method is unsupported.
TypeError: Request with GET/HEAD method cannot have body.
The Fetch standard uppercases only DELETE, GET, HEAD, OPTIONS, POST and PUT, so patch stays lowercase and can return 405. It also forbids CONNECT, TRACE and TRACK, and Node refuses a body on GET or HEAD.
patch is not the same as PATCH. In the run above, fetch normalized put to PUT but left patch alone, and Node printed a warning that it will likely produce a 405. Always write methods in uppercase.{"qty":2} can wipe the other fields. Use PATCH for partial changes.page?do=delete will be fetched by crawlers and prefetchers. RFC 9110 warns that the owner must disable unsafe actions on safe methods.method attribute accepts get, post and dialog. Other methods need fetch or a hidden _method field handled by your framework.Allow header. Use 501 only when the server does not know the method at all.