TT Lab
Get started
Learn Learning paths Courses

FastAPI — Types Are the Contract

Design principles: Prevent lost updates with ETags

Continue in TT Lab

Summary

To prevent lost updates, the condition "modify only if it is the version I read" has to be carried all the way into the database's write statement.

Why this matters

A and B read the same note at v1. After A edits the title, if B saves from a stale screen, an unconditional UPDATE silently overwrites A's change. Even if you check the version with a SELECT just before saving, another request can slip in between the check and the UPDATE. The comparison and the update have to be bound into a single SQL statement, and you have to check the number of rows changed. Here we actually open a SQLite file and make two requests on separate connections race each other. We do not test only a dictionary in process memory.

How it works

GET → ETag: "v1"
  ├─ A: PUT If-Match "v1" → UPDATE WHERE version=1 → 204, version=2
  └─ B: PUT If-Match "v1" → 변경 행 0             → 412

An ETag is a validator of a representation. In this lab we build a strong tag under the restriction that, per id, the version increases exactly when the title changes and no other part of the response representation changes. In a real service, if the compression, language, or per-permission fields of the representation differ, you must not reuse the same version string unconditionally.

What it looks like in the field

If-Match uses strong comparison. This teaching API accepts only a single tag and does not support weak tags, wildcards, or lists. This is not an implementation of the full HTTP grammar; it is a narrow contract stated explicitly by the API. We define 404 for a note that does not exist, 428 for a missing condition, and 412 for an unsupported condition or a stale version. The client must not retry a 412 endlessly; it has to read the latest note and ask the user to merge. An empty title, which is an input error, is distinguished as 422.

What you will do in the next lab

You complete it in this order: schema, create, read, tag, condition parsing, atomic update, result codes, then FastAPI. You also check that the original title is preserved. An implementation that gets only the number 412 right and then runs the UPDATE afterward must not pass. Close the DB connection after every operation to prevent state from leaking between tests.

See also: HTTP conditional requests