Skip to content
death.tech home
All recent changes

Make optimistic locking work: ETags follow the record version

b64db27fix(customers)merged 5d ago1 review thread

Illustrative: based on a real change, edited for clarity and privacy.

src/adapters/primary/fastapi/routes/address/get.py+5 −2

Changes to src/adapters/primary/fastapi/routes/address/get.py. Lines with review comments are numbered.
@@
33from fastapi import APIRouter, Header, Response, status
44
55from src.adapters.primary.fastapi.etag import (
6removed generate_etag,
6added stored_etag,
77 validate_if_none_match,
88)
99from src.adapters.primary.fastapi.models.address_attribute import (
@@ async def _get_attribute(
126128 attr = self._fetch_attribute(customer_ref, attribute_ref)
127129
128130 # Handle conditional GET with If-None-Match
129removed current_etag = generate_etag(attr.updated_at, attr.ref)
131added # The ETag is the row version, the same number If-Match is checked against
132added # on writes, so a read and a later write can never disagree about staleness.
1 line 133, review thread 1added current_etag = stored_etag(attr.version, attr.ref)
130134 if if_none_match is not None and validate_if_none_match(
131135 if_none_match, current_etag
132136 ):
@@ async def _get_attribute(
137141 )
138142
139143 # Build full response
144added response.headers["ETag"] = current_etag
140145 return AddressAttributeResponse.from_dto(attr)
141146
142147 async def _head_attribute(
    1. AI reviewP1

      Relationship changes keep old ETags

      A PATCH that only changes an address label or the primary flag updates the relationship, not the attribute, but this ETag only uses the attribute’s version. A client can get a 304 for stale data, or make a later write with an old If-Match that still passes.

    2. author

      Fixed: a link change now marks the attribute as updated, so changing the label, primary flag or grouping moves its version and ETag. A new test covers a stale If-Match after a label-only change, which now returns 412.

    3. reviewer

      Nice. Can the 412 go in the API docs too, so client teams know to refetch and retry?

    4. author

      Done: the endpoint docs now describe the 412 and what to do about it.

We’d like to use PostHog to see how this site gets used. It sets cookies, so it stays off until you allow it; everything else works without. Privacy notice