| |

REST API 03 ๐ŸŒ HTTP Methods (GET, POST, PUT, PATCH, DELETE)

โฑ๏ธ Estimated read: 12 min | |

HTTP methods are the verbs of a REST API. The URI identifies the resource; the method identifies what to do with it. This separation is the core of the uniform interface constraint: the same URI can support multiple operations, and the operation is expressed by the method rather than by a verb in the path . The five methods that matter for REST are GET, POST, PUT, PATCH, and DELETE, and each has a precise contract that determines whether it is safe, idempotent, cacheable, and what status codes it should return.

The distinction between PUT and PATCH is the one that causes the most confusion. PUT replaces the entire resource with the representation in the request body. PATCH applies a partial modification. If you send only the name field in a PUT request, the other fields are set to null or their defaults; if you send only the name in a PATCH request, the other fields are unchanged . The choice between them is a design decision that depends on whether the client has the full representation or only the fields that changed.

Key point: GET retrieves and is safe and idempotent; POST creates and is neither safe nor idempotent; PUT replaces the entire resource and is idempotent but not safe; PATCH partially updates and is not guaranteed idempotent; DELETE removes and is idempotent but not safe. Safety means the method does not change server state; idempotence means repeating the request produces the same result.


Why the method contract matters

The safety problem. A safe method does not change the server’s state. GET is safe: fetching a user does not modify the user. HEAD and OPTIONS are also safe. The safety guarantee is what allows a browser to prefetch a link, a crawler to follow it, or a proxy to cache it without worrying that the request has side effects . A GET endpoint that deletes a resource when called violates this contract and breaks every assumption that caches and crawlers make.

The idempotence problem. An idempotent method produces the same result when called multiple times. PUT /users/42 with the same body twice leaves the resource in the same state as calling it once. DELETE /users/42 twice: the first call deletes the resource, the second returns 404, but the server’s state is the same as after the first call . POST /users is not idempotent: calling it twice creates two users. The idempotence guarantee is what allows a client to retry a request after a network timeout without checking whether the original request succeeded.

The cacheability problem. Only GET and HEAD are cacheable by default. A GET response can be stored by the browser, a proxy, or a CDN and reused for later requests. A POST response is not cached, because the next POST might create a different resource . The Cache-Control header can override the default, but the method’s cacheability is the starting point.

The status code problem. Each method has a set of expected status codes. GET returns 200 OK or 404 Not Found. POST returns 201 Created with a Location header pointing to the new resource, or 200 OK if the result is returned in the body. PUT returns 200 OK or 204 No Content. PATCH returns 200 OK or 204 No Content. DELETE returns 204 No Content or 200 OK . Using the wrong status code is the second most common REST API mistake after putting verbs in URIs.


a. GET: retrieve a representation

GET retrieves a representation of a resource. It is safe (does not change state), idempotent (calling it twice has the same effect as once), and cacheable (responses can be stored). It should never have a request bodyโ€”the HTTP specification says the semantics of a body on a GET request are undefined, and some servers and intermediaries reject it .

GET /users/42 HTTP/1.1
Host: api.example.com
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=300
ETag: "abc123"

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

The Accept header tells the server what representation formats the client can handle. The Cache-Control and ETag headers are the caching contract. If the client sends a second request with If-None-Match: "abc123" and the resource has not changed, the server returns 304 Not Modified with no body.

GET on a collection returns a list. GET on an individual resource returns one representation. GET on a non-existent resource returns 404 Not Found. A GET request that returns 200 OK with an error message in the body is a violation of the contractโ€”the status code must reflect the outcome.


b. POST, PUT, and PATCH: the write methods

POST creates a new resource in a collection. The URI is the collection, not the individual resource, because the server assigns the identifier. The response includes the Location header with the new resource’s URI.

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

{
  "name": "Bob",
  "email": "bob@example.com"
}

HTTP/1.1 201 Created
Location: /users/43
Content-Type: application/json

{
  "id": 43,
  "name": "Bob",
  "email": "bob@example.com"
}

POST is neither safe nor idempotent. Calling it twice creates two users. This is why clients must not retry a POST blindly after a timeoutโ€”the original request may have succeeded, and a retry would create a duplicate. The Idempotency-Key header is one solution: the client generates a unique key, and the server treats requests with the same key as the same operation .

PUT replaces the entire resource. The URI is the individual resource, and the body contains the full representation. If the client sends only some fields, the missing fields are set to null or their defaults.

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

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

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

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

PUT is idempotent: sending the same body twice leaves the resource in the same state. It is not safe. If the resource does not exist, PUT can create it at the specified URI, which is why some APIs use PUT for upserts. The decision of whether PUT creates or returns 404 depends on the API’s design.

PATCH partially updates the resource. The body contains only the fields that should change. The format of the body is not standardized by HTTP; the two common formats are JSON Merge Patch (application/merge-patch+json) and JSON Patch (application/json-patch+json) .

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

{
  "email": "alice.new@example.com"
}

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

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

JSON Merge Patch is the simpler format: the body is a partial representation, and the fields present are updated, the fields absent are unchanged. JSON Patch is more expressive: the body is an array of operations (add, remove, replace, move, copy, test), each with a path and a value. JSON Patch is not idempotent in general because the operations can depend on the current state, but it can be used idempotently if the operations are designed that way.


c. DELETE: remove a resource

DELETE removes a resource. It is idempotent: deleting the same resource twice has the same effect on the server’s state as deleting it once. The first call returns 204 No Content or 200 OK; the second returns 404 Not Found because the resource no longer exists. The server state is the same after both calls, which is why DELETE is considered idempotent despite the different status code .

DELETE /users/42 HTTP/1.1
Host: api.example.com

HTTP/1.1 204 No Content

DELETE is not safe, because it changes the server’s state. It should not have a request body in most casesโ€”the URI identifies the resource, and the method identifies the action. A soft delete (marking the resource as deleted without removing it) is a common pattern, but it changes the semantics: a soft-deleted resource may still be returned by GET unless the API filters it out.

The response for DELETE should be 204 No Content if there is no body to return, or 200 OK with a body if the server returns a summary of the deletion. Returning 200 OK with an empty body is technically valid but less common than 204.


Complete Example Session

The following session demonstrates all five methods against a single resource and shows the status codes and headers for each.

// ============================================
// PART 1: CREATE (POST)
// ============================================
POST /users HTTP/1.1
Content-Type: application/json

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

HTTP/1.1 201 Created
Location: /users/42
Content-Type: application/json

{ "id": 42, "name": "Alice", "email": "alice@example.com" }
// POST creates a new resource; the server assigns the ID

// ============================================
// PART 2: RETRIEVE (GET)
// ============================================
GET /users/42 HTTP/1.1
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=300
ETag: "v1"

{ "id": 42, "name": "Alice", "email": "alice@example.com" }
// GET is safe, idempotent, and cacheable

// ============================================
// PART 3: REPLACE (PUT)
// ============================================
PUT /users/42 HTTP/1.1
Content-Type: application/json

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

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

{ "id": 42, "name": "Alice Smith", "email": "alice.smith@example.com" }
// PUT replaces the entire resource

// ============================================
// PART 4: PARTIAL UPDATE (PATCH)
// ============================================
PATCH /users/42 HTTP/1.1
Content-Type: application/merge-patch+json

{ "email": "alice.new@example.com" }

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

{ "id": 42, "name": "Alice Smith", "email": "alice.new@example.com" }
// PATCH updates only the provided field; name is unchanged

// ============================================
// PART 5: REMOVE (DELETE)
// ============================================
DELETE /users/42 HTTP/1.1

HTTP/1.1 204 No Content
// DELETE removes the resource; no body is returned

// ============================================
// PART 6: IDEMPOTENCE IN PRACTICE
// ============================================
DELETE /users/42 HTTP/1.1

HTTP/1.1 404 Not Found
// The second DELETE returns 404, but the server state
// is the same as after the first call, so DELETE is idempotent

// POST /users twice:
POST /users HTTP/1.1
{ "name": "Bob", "email": "bob@example.com" }
// โ†’ 201 Created, Location: /users/43

POST /users HTTP/1.1
{ "name": "Bob", "email": "bob@example.com" }
// โ†’ 201 Created, Location: /users/44
// Two resources created, so POST is not idempotent

The six parts demonstrate each method’s contract: POST creates and returns 201 with a Location header; GET retrieves and returns 200 with caching headers; PUT replaces and returns 200; PATCH partially updates and leaves other fields unchanged; DELETE removes and returns 204; and the idempotence comparison shows that DELETE twice has the same server state while POST twice creates two resources.


Quick Reference

Method Properties

MethodSafeIdempotentCacheableHas Body
GETYesYesYesNo
POSTNoNoNoYes
PUTNoYesNoYes
PATCHNoNot guaranteedNoYes
DELETENoYesNoNo

Status Codes by Method

MethodSuccessError
GET200 OK404 Not Found
POST201 Created + Location400 Bad Request, 409 Conflict
PUT200 OK or 204 No Content404 Not Found, 409 Conflict
PATCH200 OK or 204 No Content404 Not Found, 422 Unprocessable
DELETE204 No Content or 200 OK404 Not Found

PUT vs PATCH

AspectPUTPATCH
ScopeFull replacementPartial update
Missing fieldsSet to null/defaultUnchanged
IdempotentYesNot guaranteed
Media typeapplication/jsonapplication/merge-patch+json or application/json-patch+json

Choosing a Method

GoalMethod
Read a resourceGET
Create a new resourcePOST
Replace a resource entirelyPUT
Update specific fieldsPATCH
Remove a resourceDELETE

Best Practices

โœ… Do This:

GET    /users/42          # Safe, idempotent, cacheable
POST   /users             # Create, return 201 + Location
PUT    /users/42          # Full replace, idempotent
PATCH  /users/42          # Partial update with merge-patch
DELETE /users/42          # Idempotent remove, 204

โŒ Don’t Do This:

GET  /users/42/delete         # Action in URI, violates safety
POST /users/42                # Creating at an existing ID
PUT  /users/42 { "name": "x" } # Partial body to PUT loses other fields
GET  /users/42 with body      # Body on GET is undefined
POST twice as a retry         # Creates duplicates

Common Pitfalls

PitfallWhy It HappensFix
GET with side effectsUsing GET to deleteUse DELETE
PUT with partial bodyConfused with PATCHSend full representation or use PATCH
POST retry creates duplicatesNot idempotentIdempotency-Key header
Wrong status codeReturning 200 for errorsUse 4xx/5xx
PATCH without media typeAmbiguous formatSet Content-Type

Real-World Examples

1. Get a resource

GET /users/42

2. List a collection

GET /users

3. Create a resource

POST /users

4. Replace a resource

PUT /users/42

5. Partial update

PATCH /users/42

6. Delete a resource

DELETE /users/42

7. Merge patch media type

Content-Type: application/merge-patch+json

8. Create response with Location

HTTP/1.1 201 Created
Location: /users/43

9. Delete response

HTTP/1.1 204 No Content

10. Idempotency key

Idempotency-Key: 9c1f-4e2a

Visual

Method Properties

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SAFE (no state change)                      โ”‚
โ”‚  GET, HEAD, OPTIONS                          โ”‚
โ”‚                                              โ”‚
โ”‚  IDEMPOTENT (same result if repeated)        โ”‚
โ”‚  GET, PUT, DELETE, HEAD, OPTIONS             โ”‚
โ”‚                                              โ”‚
โ”‚  POST: neither safe nor idempotent           โ”‚
โ”‚  PATCH: not guaranteed idempotent            โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

PUT vs PATCH

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Resource: { name: "Alice", email: "a@x" }   โ”‚
โ”‚                                              โ”‚
โ”‚  PUT /users/42                               โ”‚
โ”‚  { "name": "Bob" }                           โ”‚
โ”‚  โ†’ { name: "Bob", email: null }              โ”‚
โ”‚  (email lost because PUT replaces)           โ”‚
โ”‚                                              โ”‚
โ”‚  PATCH /users/42                             โ”‚
โ”‚  { "name": "Bob" }                           โ”‚
โ”‚  โ†’ { name: "Bob", email: "a@x" }             โ”‚
โ”‚  (email unchanged because PATCH merges)      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Idempotence

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  PUT /users/42 { "name": "Bob" }  โ†’ state A  โ”‚
โ”‚  PUT /users/42 { "name": "Bob" }  โ†’ state A  โ”‚
โ”‚  (same result, idempotent)                   โ”‚
โ”‚                                              โ”‚
โ”‚  POST /users { "name": "Bob" }   โ†’ 2 users   โ”‚
โ”‚  POST /users { "name": "Bob" }   โ†’ 3 users   โ”‚
โ”‚  (different result, not idempotent)          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Status Code Flow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  POST โ†’ 201 Created + Location               โ”‚
โ”‚  GET  โ†’ 200 OK (or 404)                      โ”‚
โ”‚  PUT  โ†’ 200 OK (or 204)                      โ”‚
โ”‚  PATCHโ†’ 200 OK (or 204)                      โ”‚
โ”‚  DELETEโ†’ 204 No Content (or 404)             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
GETSafe, idempotent, cacheable, no body
POSTCreates, not safe, not idempotent
PUTReplaces entire resource, idempotent
PATCHPartial update, not guaranteed idempotent
DELETERemoves, idempotent
POST success201 Created + Location
DELETE success204 No Content
PUT/PATCH success200 OK or 204
SafetyNo state change
IdempotenceSame result if repeated

Key takeaways:

  • The method is the verb; the URI is the noun. The same URI supports multiple methods, each with a different contract. The action is never in the path .
  • GET is safe, idempotent, and cacheable. It must not change server state and must not have a body. A GET with side effects breaks caches, crawlers, and prefetching .
  • POST is neither safe nor idempotent. It creates a new resource, and calling it twice creates two resources. Retries require an Idempotency-Key or a client-side check .
  • PUT replaces; PATCH updates. A PUT request with a partial body nulls out the missing fields. A PATCH request with a partial body leaves the missing fields unchanged. The choice depends on whether the client has the full representation .
  • DELETE is idempotent despite the status code. The first call returns 204, the second returns 404, but the server state is the same after both. This is the definition of idempotence .
  • Status codes are part of the contract. POST returns 201 with Location, GET returns 200 or 404, DELETE returns 204, and errors return 4xx or 5xx. A 200 with an error body is a violation .

Remember: HTTP methods are not arbitrary labels. Each has a precise contractโ€”safe or not, idempotent or not, cacheable or notโ€”and the contract determines how clients, caches, and intermediaries treat the request. GET retrieves and is safe. POST creates and is not idempotent. PUT replaces and is idempotent. PATCH partially updates and is not guaranteed idempotent. DELETE removes and is idempotent. The PUT/PATCH distinction is the one that causes the most bugs: a partial body sent to PUT silently nulls the missing fields, while the same body sent to PATCH leaves them unchanged. The status codes are not decorationโ€”they are how the client knows whether the request succeeded, and returning 200 for every outcome defeats the entire purpose of the protocol.



Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!