An If-Match precondition lets a client require a specific representation revision before a write is accepted.
Python Flask If-Match: reject a stale in-memory revision before mutation
Operation contract
The local test client first reads a quoted revision tag, then sends an update with that tag. The handler checks it before changing the receipt amount and increments the revision. Replaying the old tag returns 412 and leaves the new amount intact. This shows an optimistic conflict boundary without opening a network listener.
Failure and ownership boundary
This in-memory state is not durable and is shared only within this fixture. Real handlers must authenticate the caller, apply tenant scope and make the compare-and-update atomic in the persistent store. Python Flask ETag responses: preserve cache validators across conditional reads, Flask SQLite application: own the request connection and verify a clean reopen and Data & Transactions show the next layer.
Tested environment
Dependency check: this program was executed on CPython 3.14.6 with Flask==3.1.3. Install these versions in a separate virtual environment. The download includes the recorded environment snapshot; no third-party package is part of the website runtime.
Working program
from flask import Flask, jsonify, request
application = Flask(__name__)
receipt = {"minor": 125, "revision": 1}
@application.get("/receipt")
def read_receipt():
response = jsonify(minor=receipt["minor"])
response.headers["ETag"] = f'"{receipt["revision"]}"'
return response
@application.put("/receipt")
def update_receipt():
if request.headers.get("If-Match") != f'"{receipt["revision"]}"':
return jsonify(error="stale revision"), 412
payload = request.get_json(silent=True)
if type(payload) is not dict or type(payload.get("minor")) is not int or not 0 <= payload["minor"] <= 1000:
return jsonify(error="invalid amount"), 400
receipt["minor"] = payload["minor"]
receipt["revision"] += 1
return jsonify(minor=receipt["minor"])
with application.test_client() as client:
tag = client.get("/receipt").headers["ETag"]
print("accepted:", client.put("/receipt", json={"minor": 150}, headers={"If-Match": tag}).status_code)
print("stale:", client.put("/receipt", json={"minor": 175}, headers={"If-Match": tag}).status_code)
print("stored:", client.get("/receipt").get_json()["minor"])Output
accepted: 200
stale: 412
stored: 150Costs and limits
The dictionary comparison and update are tiny local operations. This fixture does not measure HTTP deployment latency or establish atomicity across workers; a database update needs a revision predicate in the write itself.
Common Mistakes
- An ETag is not an authentication token.
- A read-then-write check outside a transaction can race in a persistent service.
Connected lessons
Python Flask ETag responses: preserve cache validators across conditional reads, Flask SQLite application: own the request connection and verify a clean reopen, Data & Transactions.
