HTTP Methods Explained: GET, POST, PUT, PATCH, DELETE and the Semantics That Actually Matter
2026-08-17
Every HTTP request is a verb plus a noun: a method applied to a resource. Most developers know that GET fetches and POST submits — and stop there, which is exactly where the pain starts. A GET request that deletes something. A PUT request that half-updates a record. A retried POST that charges a customer twice. Each of those is a methods-semantics bug, and each is avoidable once you understand what the HTTP specification actually promises. This guide explains the methods, the three properties that govern them, and how they pair with status codes.
What an HTTP Method Actually Means
A request line like GET /users/42 HTTP/1.1 is a promise made to the server about what you’re asking for. The URL names which resource; the method names what operation you want performed on it. That separation is the whole design: the same URL means different things under different methods, which is why a single /articles/7 endpoint can read, replace, patch, and delete the same thing.
Three properties defined in RFC 9110 govern everything that follows, and almost every method bug traces back to confusing them:
- Safe — the request doesn’t change server state. Safe methods can be run by crawlers, link previews, and prefetch engines without consequences.
- Idempotent — repeating the request N times produces the same server state as doing it once. Idempotency is what makes retries safe.
- Cacheable — the response may be stored and reused by caches (browser, CDN, reverse proxy).
Memorize which method has which property, and most of the design falls into place.
The Five Methods You’ll Use Daily
GET — read a resource. Safe, idempotent, cacheable. It should return a representation and change nothing. The moment you put a mutation behind a GET endpoint — a ?action=delete query parameter, a counter increment, a login that sets a cookie — you’ve created a request that breaks every cache, prefetch, and crawler that touches it. If a URL causes side effects, it’s not a GET.
POST — create a resource, or trigger a process. Not safe, not idempotent, and only cacheable under explicit conditions. POST is the default “do something” method: create a record, submit a form, append a log line, start a job. Because the server may create a new resource each time, two identical POSTs legitimately produce two records — that’s why payment forms and order buttons need idempotency keys or deduplication on top.
PUT — replace a resource entirely. Idempotent. PUT /articles/7 means “make the state of /articles/7 exactly match this body.” Send it twice and the second is a no-op against state. The flip side is that PUT is not a partial update: if your API’s PUT handler only sets the fields present in the body, you’ve built a PATCH wearing PUT’s clothes, and two clients updating different fields will silently clobber each other.
PATCH — apply a partial change. Neither safe nor guaranteed idempotent. The body describes changes rather than the target state — {"title": "new"} updates one field. A patch like “increment the view counter” is genuinely non-idempotent: applying it twice increments twice. When you need retry safety on a PATCH, use a conditional header (If-Match with an ETag) so the server can reject a stale or replayed request.
DELETE — remove a resource. Idempotent. The notable quirk: a second DELETE on an already-gone resource is still a success. 404 Not Found is what you return when the URL never existed; 204 No Content (or 200) is fine when the resource existed and is now gone. Many naive implementations return 404 on every subsequent delete, which breaks retry loops.
The Supporting Cast: HEAD, OPTIONS, CONNECT, TRACE
- HEAD — exactly like GET, but the response has no body. It’s how you check a resource’s existence, size, and content-type without downloading it. Cacheable, safe, idempotent.
- OPTIONS — asks the server “what am I allowed to do here?” The response’s
Allowheader lists the permitted methods. Used heavily in CORS preflight. - CONNECT — establishes a tunnel (typically TLS through a proxy). You’ll rarely use it directly.
- TRACE — echoes the request back so you can see what intermediaries changed. Often disabled on production servers because it can leak sensitive headers.
Safe vs Idempotent vs Cacheable: The Matrix
| Method | Safe | Idempotent | Cacheable |
|---|---|---|---|
| GET | ✅ | ✅ | ✅ |
| HEAD | ✅ | ✅ | ✅ |
| OPTIONS | ✅ | ✅ | ❌ |
| TRACE | ✅ | ✅ | ❌ |
| PUT | ❌ | ✅ | ❌ |
| DELETE | ❌ | ✅ | ❌ |
| PATCH | ❌ | ⚠️ (not guaranteed) | ❌ |
| POST | ❌ | ❌ | ⚠️ (only with explicit freshness) |
The pattern is worth internalizing: safe methods are a subset of idempotent methods, plus OPTIONS/TRACE. And cacheable tracks safe — because a cache can only safely reuse a response if replaying it has no side effects. That’s why “use POST for everything” quietly kills your cache hit rate.
How Methods Pair With Status Codes
The method tells the server what you want; the status code tells you what happened. Common pairings:
201 Created— a POST (or a PUT that created a resource) succeeded; theLocationheader often points at the new resource.204 No Content— success with nothing to return (a DELETE, or a PUT that returns no body).202 Accepted— the request was accepted for asynchronous processing; the resource isn’t ready yet.405 Method Not Allowed— the URL exists but this method isn’t supported on it; theAllowheader lists what is.409 Conflict— the request conflicts with the current state (e.g., a PATCH fighting a concurrent edit, whenIf-Matchfails).501 Not Implemented— the server doesn’t support the method at all (e.g., a server that never implements CONNECT).
A quick mental test for the pairings: 201/204/202 are the three “it worked” answers, and which one you use communicates whether a new thing was made, nothing needs returning, or the work is still running. See the HTTP Status Codes guide for the full troubleshooting breakdown, or look up any code with the HTTP Status Reference tool.
Common Mistakes (and the Fixes)
- GET with side effects. A
GET /logoutor a GET that increments a counter. Fix: make the mutation a POST. Prefetching, crawlers, and link previews will fire it unbidden. - POST for every mutation. It’s the easiest habit, but it forfeits idempotency and cacheability. Fix: use PUT for whole-resource replacement, DELETE for removal, and reserve POST for “create new” and “run a process.”
- PUT that behaves like PATCH. Sending only changed fields to a PUT handler that merges them. Fix: either merge whole-resource semantics into PUT (requiring the full representation) or use PATCH for partial updates.
- Non-idempotent DELETE. Returning 404 for “already deleted.” Fix: treat “gone” as success for retry safety.
- Retrying POSTs without dedup. Order forms, payment hooks, and “create” calls all double-fire on a flaky network. Fix: accept an idempotency key header and reject repeats, or make the create itself idempotent (e.g., unique constraint on a client-supplied ID).
- Ignoring
Allow. When a client gets a 405, the server’sAllowheader is the contract; honor it instead of guessing the method name.
Practical Tips
- Test method semantics with a tool you control — curl is the fastest way to send an arbitrary method and inspect the exact status code and headers.
- Use HEAD before large GETs when you only need existence or size.
- Design APIs where PUT and DELETE are safe to retry, and treat POST/PATCH as retry-unsafe unless you add protection.
- Remember that browsers’
<form>supports only GET and POST — anything else needs fetch or a client library (this is why a lot of legacy backends force everything through POST). - When debugging, always ask two questions: what did I promise (method semantics)? and did the server agree (status code)?
Quick Reference
- Request = method + URL. GET reads, POST creates/processes, PUT replaces, PATCH partially updates, DELETE removes, HEAD checks without a body, OPTIONS asks what’s allowed.
- Safe: GET, HEAD, OPTIONS, TRACE. Idempotent: those plus PUT and DELETE. Cacheable: GET and HEAD (by default).
- PUT = replace whole resource, idempotent; PATCH = partial change, not guaranteed idempotent.
- DELETE of a missing resource is still success — don’t 404 “already gone.”
201 Created/204 No Content/202 Accepted= the three flavors of success;405+Allow= wrong method for this URL.- Retrying is only safe for idempotent methods — deduplicate your POSTs.