HTTP Methods Deep Dive
Safety, idempotency, and when to use PATCH vs PUT.
HTTP Methods Deep Dive
You already know what a GET is. This level is about the semantics behind every method — the contract each one makes with the server, the client, and every proxy and cache in between.
Analogy
HTTP methods are like the different forms you sign at a front desk. GET is signing the visitors' log to read a page in the binder — the binder doesn't change, you can flip through it a hundred times. POST is dropping a brand-new application into the intake tray — drop it twice and two applications get processed. PUT is replacing an entire personnel file with a fresh folder, every sheet included — do it twice with the same folder and the cabinet ends in the same state. PATCH is leaning over the file and editing one specific line with a pen. DELETE is feeding the folder through the shredder; running it again on an already-empty shelf is harmless. HEAD is asking the clerk "does that file exist and how thick is it?" without asking them to photocopy the contents. OPTIONS is asking "which of these forms am I even allowed to sign at this desk?"
Safety and idempotency
Two properties govern how methods can be used safely in distributed systems.
A method is safe if it does not change server state. A safe request can be issued freely: bookmarked, prefetched, retried, crawled. The server may still log it or track analytics, but the resource itself is unchanged.
A method is idempotent if issuing the same request N times has the same effect as issuing it once. Idempotency is what makes retry-on-failure safe. If a DELETE request times out, you can resend it — the resource is already gone.
| Method | Safe | Idempotent | Has request body |
|---|---|---|---|
| GET | Yes | Yes | No |
| HEAD | Yes | Yes | No |
| OPTIONS | Yes | Yes | No |
| PUT | No | Yes | Yes |
| DELETE | No | Yes | No |
| POST | No | No | Yes |
| PATCH | No | No* | Yes |
*PATCH can be made idempotent through careful body design, but the spec does not require it.
GET
Retrieve a resource. No body. No side effects. The server must not change state in response to a GET. This is why GET requests can be cached at every layer: by browsers, CDNs, and reverse proxies.
If you need to read data, use GET.
POST
Create a new resource, or trigger an action that does not map neatly onto a resource. POST is neither safe nor idempotent — two identical POST requests may create two records. This is intentional: submitting the same order form twice should produce two orders.
Use POST for creation and for actions where every invocation is distinct.
PUT
Replace a resource entirely. The request body must contain the complete new representation. PUT is idempotent: sending the same PUT twice leaves the resource in the same state as sending it once.
Use PUT when the client dictates the complete state of the resource and can supply all fields.
PATCH vs PUT
The distinction matters in practice.
PUT requires a complete replacement. If you omit a field, the field is removed (or set to its default). PATCH applies a partial change — only the fields in the request body are modified.
PATCH is more network-efficient and less dangerous for large resources. But it carries responsibility: the patch semantics must be defined. Common patterns are JSON Merge Patch (RFC 7396) and JSON Patch (RFC 6902).
// PATCH with JSON Merge Patch — only name changes; other fields untouched
PATCH /users/42
Content-Type: application/merge-patch+json
{ "name": "Sam Bailey" }
// PUT — the entire user object must be sent; omitted fields are cleared
PUT /users/42
Content-Type: application/json
{ "name": "Sam Bailey", "email": "sam@example.com", "role": "admin" }
Use PATCH for partial updates. Use PUT only when the client owns the full resource representation.
DELETE
Remove a resource. DELETE is idempotent: deleting a resource that no longer exists should return 204 or 404, not an error. Either way, the postcondition (the resource is gone) is satisfied.
DELETE does not have a request body in practice, though the spec allows it. Do not put body semantics on DELETE.
HEAD
HEAD is GET without the response body. The status code and all headers are identical to what GET would return — the server must not send a body. Uses:
- Check if a resource exists without downloading it.
- Read the
Content-Lengthbefore deciding whether to download. - Validate a cache entry without refetching the full response.
- Health-check an endpoint cheaply.
HEAD is underused. Build it anywhere you build GET.
OPTIONS
OPTIONS asks the server what it can do with a URL. The server responds with an Allow header listing the permitted methods:
HTTP/1.1 204 No Content
Allow: GET, POST, OPTIONS
More commonly, OPTIONS is the mechanism behind CORS preflight. Before a browser sends a cross-origin request with a non-simple method or custom headers, it sends an OPTIONS preflight to ask permission:
OPTIONS /api/users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: Authorization
The server responds with the CORS policy:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Authorization
Access-Control-Max-Age: 86400
Access-Control-Max-Age tells the browser how long to cache the preflight result. Without it, every DELETE requires a preflight round-trip.
TRACE and CONNECT
These two appear in the spec but almost never in application code.
TRACE echoes the request back so the client can see what intermediate proxies modified. It is a diagnostic tool and is disabled by most servers because it can be used in cross-site tracing (XST) attacks.
CONNECT establishes a tunnel through an HTTP proxy to a raw TCP target — most commonly used by browsers to tunnel HTTPS through an HTTP proxy:
CONNECT api.example.com:443 HTTP/1.1
Host: api.example.com:443
If the proxy allows it, it responds 200 Connection Established and then forwards raw bytes in both directions. You will encounter CONNECT in proxy configuration, not in API design.
The safe/idempotent grid
Safe?
YES NO
┌────────────┬────────────────────┐
Idempotent│ GET, HEAD, │ PUT, DELETE │
YES │ OPTIONS │ │
├────────────┼────────────────────┤
Idempotent│ │ POST, PATCH │
NO │ — │ │
└────────────┴────────────────────┘
Safe implies idempotent, but idempotent does not imply safe. Nothing occupies the safe-but-not-idempotent cell — a method that changes nothing is by definition repeatable.