Use patches that set values, and make each update conditional with ETag and If-Match.
First, choose patch documents that describe target values, not operations. A JSON Merge Patch that sets status to shipped gives the same result however many times the server applies it. Operations like "append to an array" or "increment a counter" do not.
Second, make the update conditional. An ETag is a version tag that the server sends with a resource. The steps are:
- The client reads the resource and its
ETag. - The client sends
PATCHwith theIf-Matchheader set to that ETag. - If someone else changed the resource in between, the ETag no longer matches. The server returns 412 Precondition Failed and does not overwrite the data.
This also protects retries. If the first attempt succeeded, the ETag changed. So a retried request fails the precondition and cannot apply twice.
For patches that are not idempotent, the server can also accept an Idempotency-Key header. When the same key comes again, the server returns the stored result instead of applying the patch again.
- Prefer patch formats that set values over relative operations like "increment".
- Use
ETagwithIf-Matchfor optimistic concurrency, so the update fails if someone else changed the data first. - When the ETag does not match, the server returns 412 Precondition Failed.
- An idempotency key can make non-idempotent patches safe to retry.