flashman
← All guides

JSON Merge Patch API design and safe partial updates

Design predictable JSON Merge Patch endpoints with explicit null semantics, stable object contracts, concurrency controls, validation, authorization, and test fixtures.

2026-08-30 · 8 min read

  • json
  • api-design
  • http

Partial updates reduce payload size and client coordination, but they also introduce a third state for every property: replace it, remove it, or leave it unchanged. JSON Merge Patch defines these operations with ordinary-looking JSON, which makes a precise endpoint contract essential.

The format is useful for object-shaped resources when whole-array replacement is acceptable. It is a poor fit when clients must address individual array elements or represent a stored JSON null independently from removing a member.

Define media type and null behavior

Require application/merge-patch+json and reject ambiguous content types. In Merge Patch, an object member with a null value removes that member from the target; an omitted member makes no change. Document how removal maps to required fields, database nullability, defaults, and derived values.

  • Reject removal of required or immutable properties.
  • Define whether unknown properties fail validation.
  • Explain that arrays are replaced as complete values.
  • Keep ordinary full-replacement and Merge Patch endpoints distinct.

Apply validation and authorization to the result

Parse the patch, validate its permitted shape, apply it to an authorized resource projection, then validate the resulting resource. Validating only the patch misses cross-field invariants; validating only the result may let callers attempt changes to fields they cannot edit.

Protect against prototype-related keys and unsafe object merging in implementation code. Use a standards-aware library or a deliberately small recursive implementation with fixtures from the specification instead of a generic deep-merge utility.

Prevent lost updates

A partial payload does not make concurrent writes safe. Return an ETag with the resource and require If-Match for updates that must not overwrite a newer version. On mismatch, return a conflict response and let the client fetch current state before constructing a new patch.

  • Keep authorization checks inside the same transaction as the update.
  • Write an audit record containing changed paths without exposing secrets.
  • Make retry behavior explicit; a stale patch is not automatically safe.
  • Test concurrent deletion and replacement of the same member.

Build a local contract workflow

Use Flashman's JSON formatter to inspect target, patch, and result; diff tool to show intended changes; URL tool to verify endpoint construction; case converter to catch client naming drift; and timestamp converter for ETag or version fixtures that include time.

Maintain tests for omission, deletion, nested objects, scalar replacement, arrays, immutable fields, unknown keys, malformed media types, authorization failures, stale ETags, and round trips through generated clients.

Try these tools