ASP.NET Coreで一覧APIにページングを付ける
商品が増えたあとも一覧APIが全件を返すと、転送量と画面の表示時間が増えます。最初はpageとpageSizeを受け取るページングが分かりやすい方法です。
まず入力の上限を決める
[HttpGet]
public async Task<IActionResult> FindAll(
[FromQuery] int page = 1,
[FromQuery] int pageSize = 20,
CancellationToken cancellationToken = default)
{
if (page < 1 || pageSize < 1 || pageSize > 100)
return BadRequest("pageは1以上、pageSizeは1〜100を指定してください。");
var offset = ((long)page - 1) * pageSize;
var items = await repository.FindPageAsync(pageSize, offset, cancellationToken);
return Ok(new { Page = page, PageSize = pageSize, Items = items });
}このActionは[ApiController]を付けたController内の例です。pageSizeに上限を置くのは、1回の要求で大量のデータを読み込ませないためです。計算をlongで行うとintの乗算による桁あふれを避けられますが、極端に大きいpageはAPIの要件に応じて別途拒否してください。
SQLでは順序を固定する
SELECT product_id, name, price
FROM products
ORDER BY product_id
LIMIT @limit OFFSET @offset;@limitと@offsetは、利用するDBライブラリでパラメータとして渡します。ORDER BYがないと取得順が保証されず、同じ商品が複数ページへ現れたり、抜けたりする原因になります。更新日時で並べる場合も、同じ日時の行の順序が安定するようORDER BY updated_at DESC, product_id DESCのように一意な列を最後へ加えます。
画面に「次がある」を伝える
件数の合計が不要なら、要求数より1件多く取得して次ページの有無を判断できます。たとえば20件表示するなら21件取得し、21件目があればhasNext = trueとして、画面へ返すのは先頭20件だけにします。
ページ間で商品が追加・削除されると、OFFSETの位置がずれます。大きな一覧や頻繁に更新される一覧では、最後に見たIDを次回の条件にするカーソル方式も検討します。最初から両方式を実装する必要はありませんが、OFFSETの限界は知っておきましょう。