Card 08/ 11

WalkthroughDifficulty: Advanced2 min

Optimistic Concurrency With If-Match and 412

The client sends back the ETag it read; the server refuses the write if the resource has changed since.

Optimistic concurrency prevents a lost update by making each write conditional on the version the client read. The client sends the ETag it received in an If-Match header; the server applies the write only if the resource's current ETag still matches, and otherwise refuses with 412 Precondition Failed. Here is the two agents' edit replayed with it. The ETags are illustrative.

The two agents' edit with If-Match, and the second write refused

A conditional write, step by step

Each client reads the resource and its ETag

Both agents receive the customer with ETag: "v3". Their clients keep the tag alongside the data they show.

The first write matches and succeeds

Ana's PUT carries If-Match: "v3". The current ETag is v3, so the server applies it and the customer becomes v4.

The second write no longer matches

Ben's PUT also carries If-Match: "v3", but the current ETag is now v4. The server refuses with 412 Precondition Failed and changes nothing, so Ana's address survives.

The refused client reads again and reapplies

Ben's client fetches v4, which has Ana's address, applies the phone number to it, or asks Ben to review the change, and sends the PUT with If-Match: "v4". It succeeds, and nothing is lost.

Strong ETags only. If-Match uses strong comparison, so the server must send strong ETags on any resource clients edit. A weak tag never matches, and every write would be refused.

Checking and writing at once. The server must compare the version and apply the write as one atomic operation, for example UPDATE ... WHERE id = 7 AND version = 3 in a database, and treat zero rows changed as a 412. Comparing first and writing afterwards leaves a gap where another write can slip in.

Requiring the header. A client that forgets If-Match loses updates as before. A server can refuse such writes with 428 Precondition Required, which tells the client to send the condition.

412, not 409. 412 says a precondition the client itself set has failed, so the client knows exactly why and what to do. 409 is for conflicts the client did not ask the server to check.