REST APIのページングは一覧画面の都合だけで決めない
REST API ページング設計で迷う場面は、実務ではかなり多いです。limitとoffsetで十分なのか。cursor paginationにすべきか。total countを毎回返すべきか。こうした判断は、一覧画面を表示できるかだけでは決まりません。
結論から言うと、ページング設計ではデータ量、並び順の安定性、総件数の必要性、フロントエンドの操作感を分けて考えることが重要です。特に検索条件が多い業務システムでは、最初に決めたレスポンス形式が長く使われます。
この記事では、REST APIの一覧取得を設計するエンジニア向けに、limit offset、cursor pagination、sort、total count、APIレスポンスの実務判断を整理します。薄い用語説明ではなく、レビューで見られやすい観点も扱います。
APIページング設計で最初に決めること
まず、ページング方式だけを先に決めると失敗しやすいです。画面の使い方、データの増え方、並び替えの種類を確認します。
| 観点 | 確認すること | 設計への影響 |
|---|---|---|
| データ量 | 数千件か、数百万件か | offsetの深いページが重くなる |
| 並び順 | 登録日時、更新日時、スコアなど | 同値の並び替え条件が必要になる |
| 画面操作 | ページ番号移動か、無限スクロールか | offset方式とcursor方式の向き不向きが変わる |
| 総件数 | 正確な件数が必要か | countクエリのコストが変わる |
| 検索条件 | 条件数とインデックス設計 | sortとwhereの組み合わせが重要になる |
例えば、管理画面で「3ページ目へ移動したい」要件があるなら、offset方式は扱いやすいです。一方で、タイムラインや通知一覧のように次の塊を順番に読む画面なら、cursor方式が向いています。
クエリパラメータを設計するときは、MDNのURLSearchParamsのように、URLのquery stringとしてどう扱われるかも意識します。フロントエンド側で検索条件を組み立てやすい命名にします。
limit offsetはわかりやすいが深いページに注意する
limit offset方式は、実装者にも利用者にも理解しやすい方式です。例えば、次のようなAPIです。
GET /api/orders?limit=50&offset=100&sort=createdAt,desc
ただし、offsetが大きくなるほどDB側の負荷が増えることがあります。特に複雑なwhere条件、join、ソートが絡む一覧では、見た目以上に重いSQLになります。
そのため、limit offsetを採用する場合は上限を決めます。例えば、limitの最大値を100にする。offsetが一定以上の検索には条件追加を促す。重い一覧では非同期出力に切り替える。こうした運用上の線引きも設計に含めます。
cursor paginationは順次取得に強い
cursor paginationは、次のページを取得するためのカーソルをレスポンスで返す方式です。ページ番号移動よりも、前回取得した位置から続きを読む用途に向いています。
GET /api/orders?limit=50&cursor=eyJjcmVhdGVkQXQiOiIyMDI2LTA2LTA0VDA5OjAwOjAwWiIsImlkIjoxMjM0fQ
cursor方式では、並び順とカーソルの中身を一貫させる必要があります。createdAtだけを基準にすると、同じ時刻のデータで順序が不安定になります。そのため、createdAtとidのように一意性を補う条件を持たせます。
JSON:APIのCursor Pagination Profileでも、cursorを使ったページングの考え方が整理されています。仕様をそのまま採用しない場合でも、次ページ、前ページ、並び順の扱いを考える参考になります。
sortはページング設計の一部として扱う
ページングでよくある失敗は、sortを後付けで増やすことです。並び順が変わると、ページの境界も変わります。つまり、sortは表示オプションではなく、ページング設計の一部です。
{
"items": [
{ "id": 1234, "createdAt": "2026-06-04T09:00:00Z", "status": "APPROVED" }
],
"page": {
"limit": 50,
"nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA2LTA0VDA5OjAwOjAwWiIsImlkIjoxMjM0fQ",
"hasNext": true
},
"sort": [
{ "field": "createdAt", "direction": "desc" },
{ "field": "id", "direction": "desc" }
]
}
この例では、createdAtだけでなくidも並び順に含めています。これにより、同じcreatedAtのレコードが複数あっても順序が安定します。
なお、OpenAPIで一覧APIを定義する場合は、query parameterとしてlimit、offset、cursor、sortを明示します。OpenAPI LearnのParameters and Payload of an Operationでは、operationのparameter定義が整理されています。
total countは毎回返せばよいとは限らない
総件数は便利です。画面に「全1,234件」と表示できます。ページ番号UIも作りやすくなります。
一方で、countクエリは重くなることがあります。検索条件が複雑で、joinや権限制御も入る場合、一覧取得よりcountの方が遅いこともあります。
実務では、次のように分けると判断しやすいです。
| 要件 | total countの扱い | 理由 |
|---|---|---|
| 業務上、件数確認が重要 | 返す | 承認対象件数や請求対象件数に使う |
| 無限スクロール | 返さない、または概算 | 次があるかだけで足りる |
| 重い検索条件 | 別API、遅延取得を検討 | 初期表示を遅くしない |
| 監査や帳票 | 一覧APIとは分ける | 正確性と処理時間の要件が違う |
レビューで見るREST API ページング設計のチェックリスト
- limitの最大値が決まっているか
- offset方式とcursor方式の採用理由を説明できるか
- sortの指定可能項目が明確か
- 同値ソート時の順序が安定しているか
- total countの必要性とコストを確認しているか
- レスポンスにhasNext、nextCursor、limitなどのメタ情報があるか
- 検索条件、認可条件、インデックスの組み合わせを確認しているか
よくある質問
一覧APIは最初からcursor paginationにすべきですか?
必ずしもそうではありません。ページ番号移動が必要な管理画面では、limit offset方式の方が扱いやすいことがあります。一方で、大量データを時系列で読み進める画面ではcursor方式が向いています。
total countを返さないと画面が不親切ですか?
画面要件によります。業務上の件数確認が重要なら返す価値があります。ただし、単に次ページがあるか知りたいだけなら、hasNextで足りる場合があります。
まとめ
REST APIのページング設計では、limit offsetとcursor paginationの優劣だけで決めないことが重要です。データ量、並び順、画面操作、total countのコストを分けて判断します。
- limit offsetはわかりやすいが、深いページと重い検索条件に注意する
- cursor paginationは順次取得に強いが、安定したsort設計が必要
- total countは便利だが、毎回返す前提にしない
Java/Spring BootやReactの案件では、一覧APIの設計力が開発効率に直結します。ページング、検索、ソート、レスポンス形式まで説明できる経験は、現場での信頼にもつながります。
API設計やSpring Boot案件で、今の経験をどう活かすか整理したい場合は、技術領域や働き方の希望も含めて相談できます。
一度カジュアル面談をしませんか?
株式会社bluenaは「高還元」と「伴走支援」を両立したSES企業です。単価の81〜86%を還元する報酬体系と、専任サポーターによる隔週1on1で、エンジニアが納得できるキャリアを実現します。
まとまっていなくてもOK——まずは現在地を聞かせてください。
カジュアル面談ですので、お気軽にお聞かせください。





