Methods tell caches, proxies, browsers and API clients what a request may do, and when it's safe to retry.
The method says what the client wants to do with the target resource.
GET: retrieve a representation. No body, no side effects intended.HEAD: like GET but only the headers, for checking existence, size or freshness.POST: process the enclosed data: create a resource in a collection, submit a form, trigger an action.PUT: replace the resource at this URL with the body, creating it if absent.PATCH: apply a partial modification.DELETE: remove the resource.OPTIONS: ask what's allowed; used by CORS preflight requests.
Two properties matter more than the names.
Safe methods (GET, HEAD, OPTIONS) are read-only by contract. Crawlers, prefetchers and link previews issue GETs freely, so a GET that deletes or changes data will eventually be triggered by a bot.
Idempotent methods (the safe ones plus PUT and DELETE) have the same effect whether sent once or many times. Deleting an item twice leaves it deleted; PUTting the same body twice gives the same state. Clients and proxies can therefore retry them after a timeout. POST and PATCH are not idempotent in general: retrying a POST may create two orders, which is why payment APIs add idempotency keys.
Browsers' HTML forms only send GET and POST; JavaScript's fetch can send any method. And idempotent doesn't mean the response is identical: a second DELETE may return 404.
Example
const base = "https://api.example.com/v1/articles";
await fetch(base); // GET: list
await fetch(`${base}/42`, { method: "HEAD" }); // headers only
await fetch(base, { // POST: create in collection
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Hello" }),
});
await fetch(`${base}/42`, { // PUT: replace whole resource
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title: "Hello", body: "...", tags: [] }),
});
await fetch(`${base}/42`, { // PATCH: change one field
method: "PATCH",
headers: { "Content-Type": "application/merge-patch+json" },
body: JSON.stringify({ title: "Hello again" }),
});
await fetch(`${base}/42`, { method: "DELETE" }); // idempotent: safe to retryRemember
- GET reads, POST processes/creates, PUT replaces, PATCH modifies, DELETE removes
- Safe = no side effects: GET, HEAD, OPTIONS
- Idempotent = repeating has the same effect: safe methods + PUT + DELETE
- Never change data in a GET handler
Watch out for
- Implementing 'GET /items/5/delete', which crawlers and link prefetchers will happily trigger.