検索APIをPOSTで書くと何を失うのか|HTTP QUERYメソッド(RFC 10008)から読む「安全・冪等」の宣言
検索や絞り込みのAPIを作るとき、条件が少ないうちはGETのクエリ文字列で足ります。ところが条件が増え、入れ子の条件や長いIDの一覧を渡すようになると、URLが長くなりすぎて扱いにくくなります。そこでリクエスト本文に条件を入れられるPOSTに切り替える、というのはよくある判断です。
POSTに切り替えても、検索そのものは問題なく動きます。サーバーは本文を読んで結果を返すだけだからです。では、何も失っていないのか。
この記事では、2026年6月に発行されたRFC 10008「The HTTP QUERY Method」を材料に、この問いを考えます。筆者の答えは、POSTで失っているのは機能ではなく、周囲に対する「この要求は安全で、繰り返してよい」という宣言だ、というものです。
30秒で要点
- RFC 10008は、同封した内容を「安全かつ冪等に」処理させて結果を返させるQUERYメソッドを定義した
- GETで検索条件を送る方法には、URIに載せるには大きすぎる条件で4つの問題があると、RFC自身が挙げている
- POSTで代わりにすると、そのAPIが安全で冪等な問い合わせだということが、外からは容易に分からない
- QUERYのレスポンスはキャッシュ可能と定義されたが、キャッシュキーに本文を含める必要があり、GETより本質的に複雑
- 選ぶ基準は「サーバーが何をするか」より「経路上の仕組みに何を伝えるか」(筆者の整理)
| 用語 | 意味 |
|---|---|
| API | システム連携の窓口。ここでは、検索条件を受け取って結果を返すWebの仕組み |
| RFC | インターネットの技術仕様を定める文書群。番号で呼ばれる |
| 安全(safe) | その要求によって、クライアントが対象の状態変更を求めも期待もしないこと |
| 冪等(idempotent) | RFC 10008の説明では、接続が切れた後などに、必要に応じて再試行・反復してよい性質のこと |
| キャッシュ | 一度得た応答を保存しておき、同じ要求に再利用する仕組み |
| キャッシュキー | キャッシュが「同じ要求かどうか」を見分けるために使う値 |
| 経路上の仕組み | クライアントとサーバーの間やクライアントの内部にあって、要求を中継・保存・再送・記録するもの。キャッシュやリトライ(自動再送)の処理、ログなど |
RFC 10008は何を定めたのか
RFC 10008は、IETF(インターネット技術の標準化団体)のStandards Trackという区分に属するRFCで、2026年6月に発行されました。著者はJ. Reschke(greenbytes)、J.M. Snell(Cloudflare)、M. Bishop(Akamai)の3名です。
冒頭の要約(Abstract)によれば、QUERYは、リクエスト対象に同封したコンテンツを安全かつ冪等なやり方で処理させ、その処理結果を返させるメソッドです。POSTに似ていますが、QUERYの要求は、部分的な状態変更を心配せずに自動で繰り返したり、やり直したりできる、とされています。
つまりQUERYは、「条件を本文で送れて、しかも安全・冪等だと宣言された要求」という位置を埋めるものだと読めます。
GETで条件を送るとき、何が問題になるのか
RFCは序論で、クエリの条件がURIに載せるには大きすぎる場合、GETで表すやり方は問題になると述べ、次の4点を挙げています。
- 経路上のサイズ上限が事前に分からない。HTTPの仕様は少なくとも8000オクテット(1オクテットは8ビットで、1バイトに相当)のサポートを推奨しているが、経路上のどこで上限に当たるかはあらかじめ分からない
- URIへのエンコードが非効率
- URIは、リクエスト本文よりもログに残りやすく、ブックマークにも入りうる
- 入力の組み合わせごとに、別のリソースになる
3つ目は見落とされやすい点です。検索条件に個人名やメールアドレスのような情報が含まれる場合、URIは本文よりログに残りやすいので、本文で送っていれば残らなかったかもしれない記録にも残ることになります。条件の量だけでなく、条件の中身が何かもGETを選べない理由になります。
POSTに切り替えたとき、失っているもの
では、POSTに切り替えれば解決するのか。RFCはこの代替についても触れています。POSTを使う場合、要求を送る先のリソースとサーバーについての具体的な知識がなければ、安全で冪等な問い合わせが行われていることは容易には分からない、という指摘です。
ここを筆者はこう読みます。POSTの検索APIは、サーバーの中では何も書き換えていないかもしれません。しかしそれを知っているのはAPIを作った人だけで、メソッドの名前からは周囲に伝わりません。
周囲とは、たとえば次のようなものです。
- 接続が切れたときに、要求を自動で再送するかどうかを決めるクライアントやライブラリ
- 同じ要求への応答を保存して使い回すかどうかを決めるキャッシュ
- 要求をどこまで記録するかが決まっているログの仕組み
これらの仕組みが、APIの中身まで知っているとは限りません。メソッドから安全・冪等だと読み取れない以上、中身が検索であっても、それを前提に再送や保存を判断してもらうことは期待しにくいと筆者は考えます。機能は失っていませんが、周囲に対する宣言を失っています。これが「宣言」という読み替えの意味で、RFCの記述からの筆者の解釈です。
QUERYが宣言することと、その代償
QUERYは、この宣言をメソッドそのものに持たせます。RFC 10008によれば、QUERYは安全(クライアントは対象リソースの状態変更を求めも期待もしない)で、冪等(接続が失敗した後などに、必要に応じて再試行・反復してよい)です。なお、安全であっても、サーバーが追加のHTTPリソースを作ることは妨げられない、とも書かれています。
キャッシュについても定めがあります。
- QUERYのレスポンスはキャッシュ可能
- キャッシュキーには、リクエスト本文と関連するメタデータを含めなければならない(MUST)
- キャッシュの効率のために、意味の上で重要でない差異を正規化してよい(MAY)が、それはキャッシュキーを作るためだけで、リクエストそのものは変えない
ここで見落としてはいけないのは、RFC自身が添えている注意です。QUERYのレスポンスのキャッシュは、GETのキャッシュより本質的に複雑だとRFCは書いています。キャッシュキーを決めるには、リクエスト本文を最後まで読む必要があるからです。
また、QUERYのレスポンスがLocationフィールドで同じ内容を指すリソースのURIを示した場合、クライアントは以後の要求をGETに切り替えられる、とされています。重い条件は一度QUERYで送り、その結果には短いURIで何度でもGETでたどり着ける、という使い方ができるということです。
サーバーがQUERYに対応していることは、Accept-Queryレスポンスヘッダで示せます。このヘッダは、QUERYに対応していることと、使えるクエリ形式のメディアタイプ(データの種類を示す名前)を伝えるために使える、とされています。
なぜ「POSTで動いているから問題ない」と感じるのか
POSTでの検索に問題を感じにくい理由は、2つあると考えています。
1つ目に、確かめる場所がサーバーの中だけだから。開発中に確かめるのは「正しい結果が返るか」で、これはPOSTでもGETでも変わりません。キャッシュされない、再送されないといった違いは、サーバーの外で起きるので、正しく動いたかの確認には現れません。
2つ目に、問題が起きるのは異常時だから。再送の扱いが効いてくるのは接続が切れたときで、キャッシュの有無が効いてくるのはアクセスが増えたときです。どちらも平常時の動作確認では見えにくく、困ったときに初めて「なぜこの要求は再送されないのか」「なぜ毎回サーバーまで届くのか」という形で表れます。
確かなことと、まだ確かではないこと
RFC 10008の本文で確認したこと:
- QUERYは安全かつ冪等で、レスポンスはキャッシュ可能と定義されている
- キャッシュキーには本文を含める必要があり、GETより本質的に複雑だとRFC自身が書いている
LocationによるGETへの切り替えと、Accept-Queryヘッダが定められている
本記事では確認していないこと:
- 主要なWebサーバー、ブラウザ、HTTPクライアントのライブラリ、CDN(配信の高速化ネットワーク)がQUERYに対応しているか
- 特定のフレームワークや配信サービスでの設定方法
そのため、「QUERYに変えればキャッシュが効く」とは言えません。キャッシュ可能だと定義されたことと、自社の経路で実際にキャッシュされることは別の問題です。
自社の検索APIで、失っている宣言を確かめる手順
POSTで作っている検索APIを1つ選び、次の3つを確かめてください。
- そのAPIは本当に安全で冪等か。同じ本文で2回呼んだとき、サーバー側で何かが書き換わったり、件数が加算されたりしないかを確認します。ここで「いいえ」なら、そもそも検索APIとして扱うべきではありません
- 周囲はそれを知っているか。そのAPIを呼ぶクライアントやライブラリが、接続が切れたときに自動で再送するかどうかを、設定やドキュメントで確かめます。POSTだから再送しない、という扱いになっていれば、宣言を失っている状態です
- URIに載せられない理由は何か。条件が大きいからなのか、条件にログへ残したくない情報が含まれるからなのかを書き出します。前者なら、
Locationの考え方にならって、結果に短いURIを与える設計も選択肢になります
1が「はい」で2が「再送しない」なら、そのAPIは中身と扱いがずれています。QUERYへの移行を考えるかどうかは、自社の経路がQUERYに対応しているかを確かめたうえでの判断になりますが、少なくともずれがあることはこの3つで見えるようになります。
再送してよい処理かどうかを決める考え方は冪等性とは?「もう一度送っていい処理か」を決めていないAPIの弱点で、キャッシュの指示の読み方はno-cacheは「キャッシュするな」ではないで扱っています。APIの方式そのものの選び方はAPI設計のベストプラクティスも参考になります。
この記事で扱ったような判断を、自社の状況に照らして整理したい場合は、無料診断ツールで状況を言語化するところから始めることができます。
状況を整理する(15分)