Implement If-Match Precondition Update in Python
A mock resource store that uses the If-Match header's ETag to guard updates, preventing overwrites from stale clients.
Python code
51 linesfrom dataclasses import dataclass
from typing import Optional
@dataclass
class Resource:
id: str
version: int = 1
data: str = ""
etag: str = "etag-1"
class MockResourceStore:
def __init__(self):
self.resources = {}
def update(self, resource_id: str, new_data: str, if_match: Optional[str] = None) -> bool:
resource = self.resources.get(resource_id)
if not resource:
return False
if if_match and if_match != resource.etag:
return False
resource.data = new_data
resource.version += 1
resource.etag = f"etag-{resource.version}"
return True
def main():
store = MockResourceStore()
store.resources["item-1"] = Resource(id="item-1")
# Successful update with matching precondition
success = store.update("item-1", "new data", if_match="etag-1")
print(f"Success with matching etag: {success}")
# Failed update with stale etag
stale = store.update("item-1", "other data", if_match="etag-1")
print(f"Success with stale etag: {stale}")
# Correct new etag works
correct = store.update("item-1", "latest data", if_match="etag-2")
print(f"Success with current etag: {correct}")
print(f"Final resource: {store.resources['item-1']}")
if __name__ == "__main__":
main()
Output
Success with matching etag: True
Success with stale etag: False
Success with current etag: True
Final resource: Resource(id='item-1', version=3, data='latest data', etag='etag-3')
How it works
The MockResourceStore.update method mimics HTTP If-Match semantics: it proceeds only when the client's ETag matches the current stored ETag. The Resource dataclass tracks a version counter that increments on every successful update, and the ETag derives from it, ensuring each write produces a fresh token. When if_match is provided but stale or missing, the update is rejected with a False return, analogous to a 412 Precondition Failed response without raising an exception. The pattern prevents lost-update problems in concurrent systems by making optimistic concurrency explicit.
Common mistakes
- Returning `True` on failed precondition instead of `False`
- Not updating the ETag after a successful update
- Ignoring the `if_match` parameter when it's `None`
Variations
- Raise a custom `PreconditionFailedError` instead of returning a boolean
- Store the ETag as a hash of the data field for additional integrity checking
Real-world use cases
- RESTful API endpoints use If-Match headers with ETags to prevent concurrent overwrites of a resource.
- Distributed caches validate version tokens before writing to avoid stale updates from replicated clients.
- Document editors send the last-seen revision ID to the server to merge changes safely under concurrency.
Sponsored
More from API design & gRPC
- Build a Bulk Array POST Mock Server in Python medium
- Build a Mock REST API with PUT and GET in Python medium
- Convert Protobuf to JSON and Dict in Python easy
- Create a Data Helper in Python for gRPC-style APIs easy
- Format data in Python using dataclasses like gRPC messages easy
- Generate an OpenAPI Spec from Mock Routes in Python easy
Keep learning
Related tutorials and quizzes for this topic.