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

FastAPI — 型がそのまま契約だ

抜け・重複のないカーソルページネーション:設計の考え方

TT Labで続きを見る

一言でいうと

ページネーションの契約は、「何件見せるか」ではなく、どの順序のどこまで読んだかです。

なぜ必要なのか

一覧の1ページ目を見たあと、新しい項目が先頭に入ってきたとします。offset=10で次のページをリクエストすると、前から押し出された項目をもう一度見てしまうことがあります。逆に、削除が挟まると、飛ばしてしまうことがあります。一意で変わらないidでソートし、最後のidより大きい行を読めば、この移動の問題を減らせます。ただし、カーソルはデータ全体のスナップショットではありません。すでに通り過ぎた区間にあとから挿入された行までは保証せず、価格順のようにソートの値が変わる一覧には、複合キーと別の契約が必要です。

どう動くのか

전체 행 → 범주 필터 → id 오름차순 → id > cursor → limit + 남은 행 확인
                                                     ↓
                                      공개 필드 투영 + next_cursor

limit=2で結果が2件だったという事実だけでは、次のページがあるとはいえません。このラボでは、残りの行がlimitより多いときだけ、最後に返したidをカーソルにします。実際のサービスのSQLでは、WHERE id > ? ORDER BY id LIMIT (limit+1)で1行多く読んで、同じ判断をします。ここでは、小さなメモリ上の一覧で、まず契約を検証します。

現場での姿

カーソルをbase64に変換しても、暗号化やアクセス制御にはなりません。デコードしたあとに正の整数かどうかを検査し、実際のサービスでは、フィルターやソートの条件にカーソルを結び付けるかどうかを決める必要があります。このラボのカーソルはidだけを含むので、次のリクエストも同じcategoryを送る必要があります。内部コストのようなフィールドを元の辞書のまま返すと、ページネーションが合っていても、データが漏れます。公開フィールドだけを新しい辞書に入れる射影を、最後に置きます。

次のラボですること

不規則なidの順序、空の一覧、ちょうど最後のページ、不正なlimitとカーソルを確認します。最後のステップでは、TestClientで2ページを続けて読み、重複・欠落・内部フィールドの露出を検査します。次のリクエストのcategoryが変わったり、ソートのキーが変更されたりすると何が変わるかを説明できてはじめて、このラボが終わりです。

参考: FastAPIのテスト