The read side saves a response body when clients cooperate; the write side prevents a lost update whether they cooperate or not.
GET /api/orders/8814
→ 200 OK
ETag: "a41f2b8"
PUT /api/orders/8814
If-Match: "a41f2b8"
→ 412 Precondition Failed # somebody else changed it
// requiring If-Match on unsafe methods turns a silent
// overwrite into an error the client must handle.
Making If-Match mandatory rather than optional is the decision that gives the guarantee, and it is a breaking change for existing clients — so it arrives with a version or a grace period. Generating the tag from a version column rather than hashing the body is cheaper and avoids rendering a response only to discover it was not needed.