REST APIs in Depth · Correctness: Errors, Validation, Concurrency and Caching

Conditional Requests, ETags and Optimistic Concurrency

Prevent lost updates and save bandwidth with validators.

An ETag is a validator identifying a specific representation version. Clients send If-None-Match to revalidate cached data (server returns 304 Not Modified), and If-Match on writes so the server applies the update only if the resource hasn't changed (412 Precondition Failed otherwise). This is optimistic concurrency over HTTP — no locks, safe for long user edits. Some APIs require If-Match on updates (428 Precondition Required when missing).

Conditional request headers

Header Used with Server response if condition fails
If-None-Match GET/HEAD (cache revalidation) 304 Not Modified
If-Match PUT/PATCH/DELETE (concurrency) 412 Precondition Failed
If-Modified-Since GET (date-based revalidation) 304
(missing If-Match) When required by policy 428 Precondition Required
@app.put("/documents/{doc_id}")
async def update_doc(doc_id: str, body: DocIn, if_match: str = Header(...), db=Depends(get_db)):
    doc = await docs.get(db, doc_id) or raise_404()
    if if_match != f'"{doc.version}"':
        raise HTTPException(412, "Document changed; reload and retry")
    doc = await docs.update(db, doc, body)              # increments version
    return JSONResponse(doc.dict(), headers={"ETag": f'"{doc.version}"'})

Common pitfalls

  • Weak ETags (W/) used for If-Match (strong comparison required for writes).
  • Generating ETags by hashing huge bodies on every request (use version columns).
  • Last-write-wins updates that silently lose edits.

Key points

  • ETag = representation version
  • If-None-Match → 304; If-Match → 412
  • Version columns make ETags cheap

Further reading: RFC 9110: Conditional requests

Practice questions

How does If-Match prevent the lost update problem?

Answer

The update only succeeds if the resource's current ETag equals the one the client read; if someone else changed it in between, the server returns 412 and the client must reload and merge.

What's the difference between strong and weak ETags?

Answer

Strong ETags change whenever the byte representation changes and are required for If-Match; weak ETags (W/"…") indicate semantic equivalence and are only suitable for cache revalidation.

Open in the app to mark lessons complete, take notes and track your progress.