Skip to content
C Codeloom
REST APIs

HTTP Methods Explained: GET, POST, PUT, PATCH, DELETE

A practical walkthrough of HTTP methods — semantics, safety, idempotency, body conventions, and the differences between POST, PUT, and PATCH. Plus OPTIONS and HEAD.

·11 min read · By Yash Kesharwani
Beginner 11 min read

What you'll learn

  • What each HTTP method means and when to use it
  • The difference between safe and idempotent — and why retries depend on it
  • When to use POST vs PUT vs PATCH (the eternal question)
  • Which methods take a body and which don't
  • The roles of OPTIONS and HEAD

Prerequisites

  • A rough idea of HTTP requests and responses
  • Useful background: What Is REST?

HTTP methods are the verbs of the web. They tell the server what the client wants to do with a resource. Most developers can name five — GET, POST, PUT, PATCH, DELETE — but the rules behind those names are what make APIs predictable, retryable, and cache-friendly.

This post walks through each method, the safety and idempotency rules, and the conventions worth following.

Safe vs idempotent — the two key terms

Two HTTP concepts come up over and over. They are easy to confuse:

  • Safe — the method does not change server state. Browsers can prefetch safe requests freely. Examples: GET, HEAD, OPTIONS.
  • Idempotent — calling the method N times has the same effect as calling it once. The client can retry safely without fear of duplicates. Examples: GET, PUT, DELETE.

Every safe method is idempotent (doing nothing once is the same as doing nothing twice). The converse is not true — DELETE is idempotent but not safe.

MethodSafeIdempotentHas bodyHas response body
GETYesYesNoYes
HEADYesYesNoNo
OPTIONSYesYesNoYes
POSTNoNoYesYes
PUTNoYesYesYes
PATCHNoNo (by spec)YesYes
DELETENoYesOptionalOptional

Keep this table near you the first few times you build an API. After that it becomes reflex.

GET — read a resource

GET asks for a representation of a resource. It must be safe: a GET should never create, modify, or delete anything.

GET /users/42 HTTP/1.1
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

{ "id": 42, "name": "Alice" }

A few conventions:

  • No request body. Servers are allowed to ignore one if you send it. Some load balancers strip it. Just don’t.
  • Cacheable by default. Browsers, CDNs, and proxies all assume GETs are cacheable unless told otherwise.
  • Idempotent and safe means a failed GET can always be retried.

If you’re tempted to “GET” something that has side effects (like marking a notification read), that’s a POST, not a GET. The web crawls everything; a GET with side effects is a foot-gun.

POST — create or act

POST is the catch-all “do something” verb. It’s the only common method that is neither safe nor idempotent. Two patterns dominate.

Create a new resource

POST /users HTTP/1.1
Content-Type: application/json

{ "name": "Alice", "email": "alice@example.com" }

HTTP/1.1 201 Created
Location: /users/42

{ "id": 42, "name": "Alice", "email": "alice@example.com" }

The server assigns the ID. The response is 201 Created with a Location header pointing to the new resource — see HTTP Status Codes Explained.

Trigger an action

POST /orders/9001/cancel HTTP/1.1

HTTP/1.1 200 OK
{ "id": 9001, "status": "cancelled" }

When the action isn’t a clean state transition (cancel, archive, retry a job), POST is the right verb. Don’t twist yourself into a noun-shaped pretzel to avoid it.

POSTs aren’t idempotent by default. If the network drops and the client retries, you might create two users. The fix is the Idempotency-Key header — covered in REST API Design.

PUT — replace a resource

PUT replaces the resource at the given URL with whatever the client sends. It is idempotent: send the same body twice, and the end state is the same.

PUT /users/42 HTTP/1.1
Content-Type: application/json

{ "name": "Alice Cooper", "email": "alice@example.com", "role": "admin" }

HTTP/1.1 200 OK
{ "id": 42, "name": "Alice Cooper", "email": "alice@example.com", "role": "admin" }

The key idea: PUT means “make the resource look like this.” If you leave out a field, you are saying “set that field to its default” — typically null or absent.

That last point catches people. PUT is not partial update. If the existing user had a bio field and your PUT doesn’t include it, the bio should be cleared.

If you want partial update, you want PATCH.

PATCH — modify part of a resource

PATCH applies a change to a resource. Only the fields you send are updated; everything else is untouched.

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

{ "role": "admin" }

HTTP/1.1 200 OK
{ "id": 42, "name": "Alice Cooper", "email": "alice@example.com", "role": "admin" }

By specification, PATCH is not guaranteed idempotent — a patch could be an instruction like “increment by 1” which isn’t idempotent. In practice, most PATCH endpoints do the simple thing (set named fields) and are de-facto idempotent.

Two PATCH conventions you’ll encounter:

  • Merge patch (RFC 7396) — send a partial JSON object; fields you include are set, fields you omit are untouched, fields set to null are cleared. Simple and common.
  • JSON Patch (RFC 6902) — send an array of explicit operations like [{ "op": "replace", "path": "/role", "value": "admin" }]. Powerful but rarely used in everyday APIs.

Stick with merge patch unless you have a specific reason.

POST vs PUT vs PATCH

The eternal question. The clearest framing:

OperationMethodIdempotent?Client supplies the ID?
Create a new resourcePOSTNoNo — server assigns
Create or replace at a known URLPUTYesYes — client supplies
Replace an existing resourcePUTYesn/a
Update some fieldsPATCHOften, but not requiredn/a
Trigger an actionPOSTNon/a

When is PUT actually used to “create”?

When the client owns the namespace. For example, an API that lets you upload a file by name:

PUT /files/avatars/alice.png
Content-Type: image/png

<bytes>

If the file doesn’t exist, PUT creates it. If it does, PUT replaces it. Both calls produce the same end state — that’s idempotency.

For resources with server-assigned IDs (almost all REST APIs in practice), creation is POST.

Try it yourself. Pick the right method for each operation on a /posts API:

  1. Get a list of posts
  2. Create a new post (server assigns the ID)
  3. Replace post 9 entirely
  4. Change just the title of post 9
  5. Delete post 9
  6. Publish post 9 (a workflow action with side effects)

Answers: GET, POST, PUT, PATCH, DELETE, POST /posts/9/publish.

DELETE — remove a resource

DELETE removes the resource at the given URL. Like PUT, it’s idempotent: calling DELETE on the same URL twice should produce the same end state (the resource is gone).

DELETE /users/42 HTTP/1.1

HTTP/1.1 204 No Content

A subtle question: what should the second DELETE return? Two valid answers:

  • 204 No Content every time — emphasises idempotency. The user is gone; the server returns success.
  • 404 Not Found on the second call — reflects that there’s no such resource any more.

Either is defensible. Many APIs return 204 on success and 404 if the resource never existed, which is a reasonable middle ground.

A DELETE can have a body (the spec recently clarified this), but treating it as bodyless is more compatible. Pass options as query parameters if you need them:

DELETE /users/42?reason=spam HTTP/1.1

HEAD — like GET, without the body

HEAD is GET with the body stripped. Same headers, same status code, no payload.

HEAD /large-file.zip HTTP/1.1

HTTP/1.1 200 OK
Content-Length: 1048576
Last-Modified: Mon, 16 Jun 2026 10:00:00 GMT
ETag: "abc123"

Use HEAD to:

  • Check if a resource exists without downloading it
  • Get the size before deciding whether to fetch
  • Validate a cached copy via ETag / Last-Modified

Most REST APIs don’t implement HEAD explicitly because web frameworks handle it automatically when GET exists.

OPTIONS — what can I do here?

OPTIONS asks the server what methods (and other capabilities) are allowed for a resource:

OPTIONS /users/42 HTTP/1.1

HTTP/1.1 204 No Content
Allow: GET, PUT, PATCH, DELETE

In the modern web, OPTIONS is best known as the CORS preflight request. Browsers fire it before a “non-simple” cross-origin request to confirm the server permits it:

OPTIONS /users HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization

If your frontend can’t reach your API, the first thing to check is the OPTIONS response and CORS headers.

Bodies and content types

Quick reminders that catch people:

  • GET and HEAD do not have bodies. Pass data via query string or headers.
  • POST, PUT, and PATCH have bodies. Set Content-Type correctly — usually application/json.
  • DELETE may have a body, but most servers and proxies don’t expect one. Prefer query parameters.
  • The response body depends on the status code. 204 means no body; 200/201 typically include one.

A common mistake on the server: trying to read req.body on a GET request. There’s nothing there.

Retries and the network

This is where safety and idempotency earn their keep.

Networks fail mid-flight. If a request times out, the client doesn’t know if the server processed it or not. What’s safe to retry?

  • GET, HEAD, OPTIONS — always safe to retry.
  • PUT, DELETE — idempotent; safe to retry, the end state is the same.
  • PATCH — usually safe; depends on the implementation.
  • POSTnot safe to retry. Two POSTs may create two resources.

For POSTs, the fix is to make them idempotent at the application level using an Idempotency-Key header. The client generates a UUID per operation; the server deduplicates by that key. See REST API Design.

This is why every serious payments API in the world supports idempotency keys. The cost of a duplicate charge is enormous; the fix is a few lines of header handling.

Try it yourself. For each scenario, decide whether the client can safely retry on a network failure:

  1. GET /users/42 timed out
  2. POST /payments (no idempotency key) timed out
  3. PUT /users/42 timed out
  4. DELETE /users/42 returned 502 from a gateway
  5. PATCH /users/42 with { "role": "admin" } timed out
  6. POST /payments with Idempotency-Key: abc-123 timed out

Answers: 1 yes, 2 no, 3 yes, 4 yes, 5 yes (it’s “set role to admin”; safe to repeat), 6 yes (the server will return the original response).

Status codes per method

A rough mapping of which status codes naturally pair with which methods:

MethodCommon success codesCommon error codes
GET200, 304401, 403, 404
POST (create)201400, 401, 403, 409, 422
POST (action)200, 202400, 401, 403, 409
PUT200, 204400, 401, 403, 404, 409
PATCH200400, 401, 403, 404, 409, 422
DELETE204401, 403, 404

For the full status code tour, see HTTP Status Codes Explained.

A pragmatic checklist

When you wire a new endpoint, ask:

  • Does the method match the intent? (GET for read, POST for action, etc.)
  • Is the operation idempotent under retry?
  • For POST that creates, does the response include a Location and 201?
  • For DELETE, do you return 204 on success?
  • For PATCH, are you using merge semantics (only sent fields change)?
  • Have you handled OPTIONS for CORS?

That’s most of the practical surface of HTTP methods.

Recap

You now know:

  • Safe means no state change; idempotent means safe to repeat
  • GET reads; POST creates or acts; PUT replaces; PATCH modifies; DELETE removes
  • HEAD is bodyless GET; OPTIONS discovers capabilities and powers CORS
  • PUT sets the whole resource; PATCH changes named fields
  • POST is the only common method that’s neither safe nor idempotent — use idempotency keys to make it retryable

Next steps

Pair this with HTTP Status Codes Every API Developer Should Know, then sweep through REST API Design: Practical Best Practices to put it all together. For a deeper look at the architectural style underneath, revisit What Is REST?.

Questions or feedback? Email codeloomdevv@gmail.com.