PUT vs PATCH — When to Use Each in REST APIs
Fast recall
Quick revision
Core answer
Whether the candidate knows the semantic difference and can explain the idempotency nuance.
Using PUT for partial updates — sending only changed fields with PUT technically violates REST semantics because PUT should replace the entire resource.
Mention that PATCH can be idempotent if implemented as absolute field assignments, but is not idempotent for relative operations like incrementing a counter.
Interview-ready guide
Interview answer
PUT and PATCH both modify resources, but they have fundamentally different semantics that affect how clients must construct requests and how servers must process them.
PUT — full replacement
- The request body is the complete new representation of the resource
- Fields missing from the body are treated as null or removed from the resource
PUT /users/1 {"name": "Alice"}— if the server follows PUT semantics strictly,emailandphoneare wiped- Clients must fetch the current state first, modify the fields they want, then PUT the complete object — expensive and racey
PATCH — partial update
- Only the fields present in the request body are modified; absent fields are untouched
- More bandwidth-efficient: only send what changed
- Idempotent when using absolute assignment (
"status": "active"); not idempotent with relative changes ("count": "+1")
JSON Merge Patch vs JSON Patch
- Merge Patch (RFC 7396): simple JSON object, fields present replace existing values, null values delete fields — this is what most APIs implement
- JSON Patch (RFC 6902): array of operation objects (
add,remove,replace) — powerful but verbose; used when atomic multi-field operations matter
In practice: use PUT when clients always know the complete state (rare), PATCH for any partial update (most common).
PUT vs PATCH — When to Use Each in REST APIs
Direct Answer
PUT replaces the entire resource with the payload you send. PATCH applies a partial update to specific fields. PUT is idempotent by definition; PATCH is technically not guaranteed to be idempotent, though most implementations make it so in practice.
Code Example
# Resource as the server currently holds it:
# GET /v1/users/42
# { "id": 42, "name": "Ada", "email": "ada@acme.com", "role": "admin" }
# --- PUT: full replacement (RFC 7231) -----------------------------------------
# You send the complete desired state. Fields you omit get reset to defaults/null.
curl -X PUT https://api.example.com/v1/users/42 \
-H 'Content-Type: application/json' \
-d '{
"id": 42,
"name": "Ada Lovelace",
"email": "ada@acme.com",
"role": "admin"
}'
# HTTP/1.1 200 OK (or 204 No Content)
# --- PATCH with JSON Merge Patch (RFC 7396) -----------------------------------
# Content-Type: application/merge-patch+json
# Only fields present in the patch are updated. `null` clears a field.
curl -X PATCH https://api.example.com/v1/users/42 \
-H 'Content-Type: application/merge-patch+json' \
-d '{
"name": "Ada Lovelace",
"role": null
}'
# After: { id:42, name:"Ada Lovelace", email:"ada@acme.com", role:null }
# --- PATCH with JSON Patch (RFC 6902) -----------------------------------------
# Content-Type: application/json-patch+json
# An *array of operations*: add/remove/replace/move/copy/test — atomic if the server
# applies them all-or-nothing.
curl -X PATCH https://api.example.com/v1/users/42 \
-H 'Content-Type: application/json-patch+json' \
-d '[
{ "op": "test", "path": "/email", "value": "ada@acme.com" },
{ "op": "replace", "path": "/name", "value": "Ada Lovelace" },
{ "op": "remove", "path": "/role" },
{ "op": "add", "path": "/tags/-", "value": "founder" }
]'
# The `test` op above gives optimistic concurrency — the patch rejects if
# the email has since changed.
# Spring Boot implementation sketches ------------------------------------------
@PutMapping("/v1/users/{id}")
UserDto replace(@PathVariable long id, @RequestBody @Valid UserDto full) {
// Idempotent: sending the same body twice yields the same state.
return userService.replace(id, full);
}
@PatchMapping(value="/v1/users/{id}",
consumes="application/merge-patch+json")
UserDto mergePatch(@PathVariable long id, @RequestBody JsonNode patch) {
UserDto cur = userService.get(id);
JsonNode merged = JsonMergePatch.fromJson(patch).apply(mapper.valueToTree(cur));
return userService.replace(id, mapper.treeToValue(merged, UserDto.class));
}
@PatchMapping(value="/v1/users/{id}",
consumes="application/json-patch+json")
UserDto jsonPatch(@PathVariable long id, @RequestBody JsonPatch patch) {
UserDto cur = userService.get(id);
JsonNode target = patch.apply(mapper.valueToTree(cur));
return userService.replace(id, mapper.treeToValue(target, UserDto.class));
}
# Quick rule of thumb:
# - Client ships full state every time -> PUT (idempotent by construction)
# - Client describes a diff -> PATCH (merge-patch for simple, json-patch for atomic ops)
Common Mistakes & Pitfalls
Using PUT for partial updates — sending only changed fields with PUT technically violates REST semantics because PUT should replace the entire resource.
Check your understanding
Answer these without looking back at the article.
- Is PATCH idempotent? Give an example where it is and where it isn't.
- How would you implement JSON Patch (RFC 6902) vs JSON Merge Patch (RFC 7386)?
- When would you choose PUT over PATCH in API design?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.