API レスポンスのページネーションは、大規模なデータセットを効率的に処理するために不可欠です。ここでは、最も一般的な戦略をいくつか紹介します。
1. オフセットベースのページネーション (SKIP/LIMIT)
- 仕組み: クライアントは
offset(スキップするレコード数) とlimit(返すレコードの最大数) パラメータを送信します。 - 利点: 実装と理解が簡単です。
- 欠点: データベースがスキップされたレコードを処理してから破棄する必要があるため、非常に大きなオフセットでは非効率的になる可能性があります。リクエスト間でデータが追加または削除された場合、一貫性のない結果につながる可能性があります (例: ある項目が複数のページに表示されたり、完全にスキップされたりする可能性があります)。
- 例:
/api/items?offset=10&limit=10(11〜20 番目のアイテムを取得)
2. カーソルベースのページネーション (Keyset Pagination)
- 仕組み: オフセットの代わりに、クライアントは「カーソル」(通常は前のページの最後のアイテムの ID またはタイムスタンプ) を送信します。次に、サーバーはこのカーソルの後のアイテムを返します。
- 利点: 前のレコードを再スキャンしないため、大規模なデータセットに対してより効率的です。リクエスト間のデータ変更 (追加/削除) に対してより堅牢で、より安定したデータ「スナップショット」を提供します。
- 欠点: 実装がより複雑になる場合があります。一貫したソート順と、カーソルとして機能する一意のシーケンシャル識別子 (またはフィールドの組み合わせ) が必要です。任意のページ番号に簡単にジャンプすることはできません。
- 例:
/api/items?after_id=12345&limit=10(ID 12345 のアイテムの後の 10 個のアイテムを取得)
3. ページベースのページネーション (ページ番号/ページサイズ)
- 仕組み: クライアントは
page_numberとpage_sizeパラメータを送信します。これは基本的にオフセットベースのページネーションのユーザーフレンドリーなラッパーです (offset = (page_number - 1) * page_size)。 - 利点: ユーザーにとって直感的で、特定のページ番号への直接ナビゲーションが可能です。
- 欠点: オフセットベースのページネーションの非効率性と不整合性を継承します。
- 例:
/api/items?page=2&page_size=10(10 個のアイテムの 2 ページ目を取得)
実装のための重要な考慮事項:
- 総数: レスポンスに
total_count(アイテムの総数) を含めるかどうかを決定します。これは「10 ページ中 1 ページ」のような UI 要素に役立ちますが、非常に大規模なデータセットの計算はコストがかかる場合があります。カーソルベースのページネーションでは、これはしばしば省略されます。 - ソート: ページネーションは、意味をなすために一貫したソート順をほぼ常に必要とします。
- エラー処理:
offsetまたはpage_numberが範囲外の場合、どうなりますか? - セキュリティ: 乱用 (例:非常に大きな
limit値) を防ぐために、ページネーション パラメータが検証されていることを確認します。 - HATEOAS (Hypermedia as the Engine of Application State): RESTful API の場合、クライアントをガイドするために、レスポンスに
next、prev、first、およびlastページへのリンクを含めることを検討してください。