HTTP Methods

What each HTTP method means, which are safe, idempotent and cacheable, and how to use them correctly in an API.

Reviewed 2026-09-16

An HTTP method (RFC 9110 calls them methods; “verbs” is the informal name) tells the server what the client wants done with the resource identified by the URL. The important properties are safe (no side effects the client is accountable for), idempotent (repeating the request has the same effect as sending it once), and cacheable. They determine how browsers, proxies and retry logic treat a request.

Summary

MethodPurposeSafeIdempotentCacheableRequest bodyDefined in
GETRetrieve a representationYesYesYesNo (allowed but has no defined meaning)RFC 9110 §9.3.1
HEADGET without the bodyYesYesYesNoRFC 9110 §9.3.2
POSTProcess data; create a subordinate resourceNoNoOnly with explicit freshness infoYesRFC 9110 §9.3.3
PUTReplace the resource with the request bodyNoYesNoYesRFC 9110 §9.3.4
DELETERemove the resourceNoYesNoRarely; no defined meaningRFC 9110 §9.3.5
CONNECTOpen a tunnel through a proxyNoNoNoNoRFC 9110 §9.3.6
OPTIONSDescribe communication optionsYesYesNoNoRFC 9110 §9.3.7
TRACEEcho the request for diagnosticsYesYesNoNoRFC 9110 §9.3.8
PATCHApply a partial modificationNoNoNoYesRFC 5789
QUERYSafe query with a body (draft)YesYesYesYesIETF draft, not yet an RFC

What safe, idempotent and cacheable mean

Safe
The client did not ask for a state change. The server may still log, count or update a cache, but the user is not responsible for it. Crawlers and link prefetchers only issue safe methods; if a GET deletes something, a crawler will delete it.
Idempotent
Sending the request N times has the same effect on the server as sending it once. The response may differ (a second DELETE returns 404), but the state does not. Clients and proxies may automatically retry idempotent requests after a network failure; they must not retry POST without knowing whether the first attempt was applied.
Cacheable
A response may be stored and reused for later equivalent requests, subject to Cache-Control. GET and HEAD responses are cacheable by default; POST responses are cacheable only when the response carries explicit freshness information, which almost nobody sends.

GET

Retrieve the current representation of the resource. Parameters go in the query string. Do not put secrets in the URL; it ends up in logs, browser history and Referer headers. Practical URL length limits are around 8 KB across servers and proxies, so large searches belong in POST (or QUERY once it is standard).

curl -i https://api.example.com/users/42
curl -i "https://api.example.com/users?role=admin&page=2"

Identical to GET but the server sends only the status and headers. Use it to check whether a resource exists, its size (Content-Length), its type, or whether it has changed (ETag, Last-Modified) without downloading it. The headers must be the same as a GET would produce.

POST

Ask the resource to process the enclosed body according to its own semantics: create a new record under a collection, submit a form, trigger an action, run a search too large for a URL. POST is the method for anything that does not fit the others. It is neither safe nor idempotent, so a browser warns before resubmitting and clients must not blindly retry.

To make a POST safely retryable, accept an idempotency key: the client sends a unique token in a header, the server stores the outcome, and a repeated request with the same key returns the stored result instead of acting again. Payment APIs work this way.

POST /orders HTTP/1.1
Content-Type: application/json
Idempotency-Key: 8b1f0c62-4d5b-4b41-9c3e-3f0e1a5d2c11

{"sku": "KB-75", "qty": 1}

HTTP/1.1 201 Created
Location: /orders/9182

PUT

Replace the entire resource at the URL with the request body. If nothing exists there, create it (201); otherwise update it (200 or 204). Because the client supplies the complete state, sending the same PUT twice leaves the same result: PUT is idempotent. Fields omitted from the body are removed, not left alone. That is the difference from PATCH; see PUT vs PATCH.

PUT requires the client to know the URL. For server-assigned IDs, POST to the collection instead.

PATCH

Apply a partial change described by the body. The body’s format defines what the change means: JSON Merge Patch (RFC 7396, application/merge-patch+json) sends only the fields to change with null to delete; JSON Patch (RFC 6902, application/json-patch+json) sends a list of operations. Many APIs accept a plain JSON subset and document the semantics themselves. PATCH is not idempotent in general (an operation like “increment” is not), though a merge patch usually is.

PATCH /users/42 HTTP/1.1
Content-Type: application/merge-patch+json

{"email": "[email protected]", "nickname": null}

DELETE

Remove the resource. Respond with 204 (done, nothing to say), 200 (done, here is a status body) or 202 (queued). A second DELETE of the same URL may return 404; that is still idempotent because the server state is unchanged. Bodies on DELETE requests have no defined meaning and some proxies drop them, so put parameters in the URL.

OPTIONS

Ask which methods and features a resource supports; the answer is in the Allow header. In browsers, OPTIONS is mostly seen as the CORS preflight: before a cross-origin request with a non-simple method or header, the browser sends OPTIONS with Access-Control-Request-Method and expects Access-Control-Allow-* headers back. A failing preflight surfaces as a CORS error in the console, not as an HTTP error.

CONNECT and TRACE

CONNECT asks a proxy to open a TCP tunnel to a host, which is how HTTPS passes through forward proxies. TRACE echoes the request back for debugging; it is disabled on most servers because it can expose cookies to cross-site scripts (“cross-site tracing”). You will rarely send either by hand.

Method not allowed and friends

  • 405 Method Not Allowed: the URL exists, this method does not apply. The response must include Allow.
  • 501 Not Implemented: the server does not know the method at all.
  • 415 Unsupported Media Type: the body’s Content-Type is wrong for this method, for example form data sent to a JSON endpoint.
  • HTML forms can only send GET and POST. Frameworks emulate PUT, PATCH and DELETE with a hidden _method field; fetch() can send any method directly.

Sending each method

curl -X PUT -H 'Content-Type: application/json' -d '{"name":"Ada"}' https://api.example.com/users/42
curl -X PATCH -H 'Content-Type: application/merge-patch+json' -d '{"name":"Ada"}' https://api.example.com/users/42
curl -X DELETE https://api.example.com/users/42
curl -X OPTIONS -i https://api.example.com/users

// fetch
await fetch("/users/42", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "Ada" }) });
navigateEnter openEsc close