TT Lab
はじめる
学ぶ 学習パス コース

FastAPI — 型がそのまま契約だ

ETagで更新の上書き競合を防ぐAPI:設計の考え方

TT Labで続きを見る

一言でいうと

「自分が読んだバージョンのときだけ更新する」という条件を、DBの書き込み文まで伝えてはじめて、更新の消失を防げます。

なぜ必要なのか

AとBが、同じメモv1を読みました。Aがタイトルを更新したあとで、Bが古い画面から保存すると、条件のないUPDATEは、Aの変更を黙って上書きします。保存の直前にSELECTでバージョンを確認しても、確認とUPDATEの間に、ほかのリクエストが割り込むことがあります。比較と更新は、1つのSQL文にまとめ、変更された行数を確認する必要があります。ここでは、SQLiteのファイルを実際に開いて、別々の接続の2つのリクエストを競合させます。プロセスのメモリ上の辞書だけを検査することはしません。

どう動くのか

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

ETagは、表現のバリデーターです。このラボでは、idごとのtitleが変わるときにversionがちょうど1増え、レスポンスの表現のほかの要素は変わらないという制限のもとで、強いタグを作ります。実際のサービスで、表現の圧縮・言語・権限ごとのフィールドが異なる場合は、同じバージョンの文字列を無条件に再利用してはいけません。

現場での姿

If-Matchは、強い比較を使います。この教育用のAPIは、単一のタグだけを受け取り、weakタグ、ワイルドカード、リストには対応していません。これはHTTP全体の文法を実装したものではなく、APIに明示した狭い契約です。存在しないメモは404、条件の欠落は428、対応していない条件や古いバージョンは412と決めます。クライアントは、412を無限にリトライせず、最新のメモを読んで、ユーザーにマージを求める必要があります。入力エラーである空のタイトルは、422として区別します。

次のラボですること

スキーマ → 作成 → 取得 → タグ → 条件の解釈 → アトミックな更新 → 結果コード → FastAPIの順に完成させます。元のタイトルが保存されているかも確認します。412という数字だけが合っていて、あとでUPDATEをしてしまう実装は、通ってはいけません。DB接続は、作業ごとに閉じて、テスト間の状態のリークを防ぎます。

参考: HTTPの条件付きリクエスト