マキモノ
開発プロセス無料✅ 公式検証済みv1.0.0 / 更新

ページングAPIで「全件取れたつもり」が4%だった — 静かな取りこぼしの検出法

limit を無視して常に20件返すAPIに対し offset を要求limit分進めていたため6,902件中280件しか取れていなかった。テストもCIも緑だった理由と、本番の意地悪さを再現するモックの書き方。

出品者: kim@orgiast.jp📖 読込 約1,365トークン (約2円)💰 コスパ 8
トークン節約メーター83%節約
ゼロからAIに作らせた場合1.4万トークン
このMDを読ませた場合2,400トークン

1.2万トークンの節約 (API料金換算で約17円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。

この巻物について

ページングAPIで「全件取れたつもり」が4%だった — 静かな取りこぼしの検出法」は、開発プロセスカテゴリのAI指示書(MDファイル)です。limit を無視して常に20件返すAPIに対し offset を要求limit分進めていたため6,902件中280件しか取れていなかった。テストもCIも緑だった理由と、本番の意地悪さを再現するモックの書き方。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約1.2万トークン(API料金換算で約17円)・83%のトークンを節約できます。

カテゴリ
開発プロセス
対応AI
claude-code、cursor、codex-cli
ライセンス
商用利用可 (再販不可)
価格
無料
ゼロから開発時
約1.4万トークン
この巻物使用時
約2,400トークン
節約量
約1.2万トークン (約17円)
更新日
2026-09-10

使い方 (AIに渡す3つの方法)

いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。

⬇ .md をダウンロード
claude "https://makimono-md.vercel.app/api/v1/files/api-4/raw を読み込んで、この指示書どおりに実装して"
claude-codecursorcodex-cliライセンス: 商用利用可 (再販不可)

中身

ページング API で「全件取れているつもり」で大半を取りこぼす事故と、その検出方法

1. 何が起きたか

認証必須の社内 <Wiki> から全ページを取得するツールを書きました。総件数は <一覧エンドポイント>totalCount として返しており、6,902 件です。

実装は「1 回のリクエストで 500 件ずつ取得し、offset を 500 ずつ進める」という素直なループでした。単体テストは全て緑、CI も緑、ローカル実行も緑。

ところが本番で実行したところ、実際に取れていたのは 280 件だけでした。取得率にして 約 4%。エラーは一切出ておらず、ツールは正常終了していました。

2. 原因

<一覧エンドポイント>limit パラメータを完全に無視し、常に 20 件だけ返す仕様でした。実測値は次のとおりです。

要求実際の返却件数
limit=100&offset=020
limit=500&offset=020
limit=100&offset=100020

一方、実装側は offset += limit(=500)で進めていました。つまり 1 回のリクエストごとに 480 件を読み飛ばしていたことになります。

計算すると 6902 / 500 ≒ 14 反復 × 20 件 = 280 件 となり、実測値と完全に一致します。取得漏れは「たまたま」ではなく、この構造から必然的に生じていました。

3. なぜテストで捕まらなかったのか

ここが本題です。テスト用のモック HTTP サーバが、「要求された limit の件数をきちんと返す」お行儀のよい実装になっていました。

そのため、テストは「実装が正しいか」ではなく 「モックが想定どおり振る舞うか」を検証していただけでした。本番の意地悪な挙動(limit を無視する)を再現できていなかったので、壊れているのに全部緑、という状態が成立していました。

モックが行儀よすぎると、テストは実装を検証せず自分の前提を検証しているだけになります。

4. 修正

  1. offset += 実際に返ってきた件数 にする。要求した limit は信用しない
  2. 返却 0 件で終了する。加えて進捗が止まったら中断するガードを入れる(同じ結果を返し続けるサーバで無限ループになるため)
  3. 取得済み ID の Set で重複排除する(一覧が更新順などの可変順序だと、同じ項目が別のページで再登場する)
  4. 取得後に必ず totalCount と突き合わせ、一致しなければ警告を出す。今回これで気づけました。数を数えない実装は、静かに壊れたまま動き続けます

擬似コードにすると次のようになります。

seen = Set()
offset = 0
while true:
    batch = fetch(offset, limit=500)   # limit は「お願い」にすぎない
    if batch.length == 0:
        break
    new_items = batch.filter(x => not seen.has(x.id))
    if new_items.length == 0:
        break                          # 進捗が止まった → 中断
    for x in new_items:
        seen.add(x.id)
    offset += batch.length             # 要求値ではなく実返却件数で進める

if seen.size != totalCount:
    warn("取得件数が総数と一致しません: {seen.size} / {totalCount}")

5. 再発防止のモック設計

  • モックは本番の意地悪さを再現する。「limit を無視して常に N 件返す」モックを 1 本用意する
  • 総数は 20 で割り切れない数(例: 130)にして、端数の扱いも検証する
  • 検証項目は次の 3 つ
    • 収集件数 == totalCount
    • 重複 0 件
    • 期待する ID の全集合と一致
  • 修正前の実装でそのテストが落ちることまで必ず確認する(落ちないテストは意味がない)
  • 「並び順が動くサーバ」のモックも用意し、複数パスで収束することを確認する

6. チェックリスト

  • offset実際に返ってきた件数で進めている(要求した limit で進めていない)
  • 返却 0 件で終了し、進捗が止まったら中断するガードがある
  • 取得済み ID の Set で重複排除している
  • 取得後に totalCount と突き合わせ、不一致なら警告を出している
  • モックに「limit を無視して常に N 件返す」意地悪なケースがある
  • 総数が割り切れない値(端数あり)でテストしている
  • 修正前の実装でそのテストが落ちることを確認済み

7. 一般化した教訓

  • ページング実装は「サーバが仕様どおり振る舞う」前提で書くと静かに壊れる
  • 総数と突き合わせない取得処理は、壊れても気づけない
  • モックが行儀よすぎると、テストは実装を検証せず自分の前提を検証しているだけになる

よくある質問

「ページングAPIで「全件取れたつもり」が4%だった — 静かな取りこぼしの検出法」とは何ですか?

limit を無視して常に20件返すAPIに対し offset を要求limit分進めていたため6,902件中280件しか取れていなかった。テストもCIも緑だった理由と、本番の意地悪さを再現するモックの書き方。

どれくらいトークン(費用)を節約できますか?

ゼロから開発すると約1.4万トークンかかりますが、この巻物を使えば約2,400トークンで済みます。差し引き約1.2万トークン(API料金換算で約17円)・83%の節約です。

どうやって使いますか?

無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。

どのAIツールに対応していますか?

claude-code、cursor、codex-cli に対応しています。

商用利用できますか?

ライセンスは「商用利用可 (再販不可)」です。

🤝 自分でAIを動かすのは、まだ不安…という方へ

この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。

AI代行堂を見る →

関連する巻物

この巻物、誰かのトークンも救えます

𝕏 で節約レシートをシェア