Skip to content
Muhammet Şafak
tr
Asked by: Bora Answered:

Should I use JSON Merge Patch or JSON Patch for partial updates?


Question

We have a Laravel-based REST API and resource updates go through `PUT`. The client has to send the whole resource every time; even the mobile app, which only wants to change a single field, sends the entire object back. The problem: when two users edit the same profile almost simultaneously, the second `PUT` overwrites the fields the first one changed, resetting them to their old values. Classic lost update. I'm thinking of moving to partial updates (`PATCH`), but should I pick JSON Merge Patch or JSON Patch, and what's the practical difference between them?

Answer

Short answer

Separate the two jobs first — choosing a PATCH format is one thing, fixing the lost update is another.

Context

On the format side, JSON Merge Patch covers most CRUD; the lost update itself is solved not by the format but by conditional requests (ETag/If-Match).

Why

  1. JSON Merge Patch (RFC 7396) is simple and covers the majority of cases. Its media type is application/merge-patch+json. You send only the fields you want to change and leave the rest untouched. It’s easy to read and produce; it’s the right tool for the typical “update these two fields” scenario.

  2. JSON Patch (RFC 6902) is powerful but expensive. It’s an array of operations: add, remove, replace, move, copy, test. It can target a specific array element via path, and with test you can even say “apply only if this value is still X”. The price is that it’s noticeably harder to produce, validate and read on both ends.

  3. Know Merge Patch’s two traps. First: null means “delete this field”, so you can’t distinguish deliberately setting a field to null from removing it. Second: arrays are replaced wholesale — there is no element-level patch. If either need is real, move to JSON Patch.

What to do

  1. The real problem is solved by concurrency control, not the format. Moving to PATCH shrinks the body but does nothing to stop two concurrent writes from clashing. For that, use an ETag + If-Match header or a version column: the client echoes back the ETag it read, and the server returns 412 Precondition Failed if it changed. JSON Patch’s test op can do the same, but ETag is cleaner at the HTTP layer.

    # Update only display_name, guarding the write with an ETag
    curl -X PATCH https://api.example.com/users/42 \
      -H "Content-Type: application/merge-patch+json" \
      -H 'If-Match: "a1b2c3"' \
      -d '{"display_name": "Bora"}'
  2. Adapt validation to the partial body. In Laravel, your PUT’s required rules break under PATCH; switch to sometimes (“validate if present”), otherwise a missing field will error.

Bottom line: personally I’d default to Merge Patch + ETag/If-Match — together they shrink the body and kill the lost update at the root. Only where I genuinely need element-level array edits or atomic conditional multi-field ops would I switch those specific endpoints to JSON Patch. Don’t mistake the format choice for the lost-update fix on its own; even with PATCH, without conditional requests you’ll hit the same race.

Comments

Sign in with your GitHub account to join the discussion. Comments are stored in GitHub Discussions.

More Questions

All questions

Search the site

Start typing to search posts, projects and pages.

Esc to close Powered by Pagefind