HTTP Semantics
Methods as promises: safety, idempotency, and what retries, proxies and caches are allowed to assume. Status codes that mean something, conditional requests, and caching as part of the contract.
Every lesson below names the consumers, the design question and the guarantee before recommending anything. Recommendations come with what they cost, when not to use them, and how they evolve.
Safe means "calling this changes nothing"; idempotent means "calling this twice equals calling it once". Retrying clients, proxies, caches and crawlers all act on those promises without asking — which is why breaking them breaks things you have never heard of.
GET promises that reading changes nothing — a promise browsers, caches, crawlers and prefetchers spend billions of requests a day relying on. GET /deleteUser?id=42 is not a style violation; it is an open invitation to every robot on the internet.
POST is HTTP's "here, process this" — creation, commands, complex reads, batch submissions. Its defining property is what it refuses to promise: idempotency. Every POST that matters needs an answer to "what if this arrives twice?", because it will.
PUT replaces the whole representation and is idempotent by construction; PATCH applies a partial change and is only as safe as your merge rules. The hard part is not choosing between them — it is saying what null means, and what absent means.
Hard delete, soft delete, async purge — three different promises hiding behind one method. DELETE is idempotent (the retry that gets 404 still succeeded), but what deletion *means* — recoverable? invisible? eventually erased? — is a domain contract HTTP cannot write for you.
The first digit answers "who acts next?" — that is the real contract. You need the dozen codes clients actually branch on, used honestly, far more than you need the other forty memorized.
One mechanism, two superpowers: If-None-Match turns repeat reads into 200-byte 304s, and If-Match turns racing writes into honest 412s. The validator — the ETag — is a contract about when a representation counts as changed.
Cache-Control is not a performance knob — it is a promise about staleness: who may store this response, for how long, and what "fresh enough" means. The most expensive header in HTTP is the one that let a shared cache store a private response.