1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

新しいHTTP QUERYメソッド

1
Posted at

IETFは、2026年6月に RFC 10008 (The HTTP QUERY Method) を正式に標準化しました。これは約16年ぶりとなる新しい標準的なHTTPメソッドの追加です。新しいHTTPメソッド QUERY は、検索APIの設計における長年のジレンマ(GET と POST のトレードオフ)を解消するために誕生しました。今回は、この QUERY メソッド登場までの長い歴史と具体的な使い方、そして Postman での設定方法を見ていきたいと思います。

はじめに

新しいHTTPメソッドが標準化されるのは、そう頻繁にあることではありません。日常的に使われている GET / POST / PUT / DELETE / PATCH のうち、最後に加わった PATCH は RFC 5789(2010年3月)でした。つまり QUERY は、約16年ぶりに標準トラックへ加わった新しいHTTPメソッドということになります。

一点だけ用語を正確にしておくと、RFC 10008 のステータスは Proposed Standard(提案標準) です。これは Standards Track の最初の段階で、HTTP/1.1・HTTP/2・HTTP/3 自体と同じプロセス(公開レビューを経て IESG が承認)を通った正式な仕様です。「まだドラフト」でも「ベンダー独自拡張」でもなく、HTTPの仕様としては十分にオフィシャルなものだと考えて差し支えありません。

著者は Julian Reschke(greenbytes)、James M. Snell(Cloudflare)、Mike Bishop(Akamai)の3氏。Cloudflare と Akamai という CDN 側の顔ぶれが並んでいるのは、後述する普及の道筋を考えるうえでも示唆的です。

背景:検索APIの長年のジレンマ

REST API を書いていると、遅かれ早かれ「検索・フィルタ用のエンドポイント」をどう設計するかという問題にぶつかります。そして、いつも2つの不完全な選択肢の間で悩むことになります。

GET の限界

素直に考えれば、データを「読み取る」だけなので GET が自然でしょう。

GET /feed?q=foo&limit=10&sort=-published HTTP/1.1
Host: example.org

GET は安全(safe)・冪等(idempotent)で、URI がリソースを完全に識別するのでキャッシュもリトライも自然に効きます。

ここでの safe(安全) は、HTTP の意味論を定める RFC 9110「HTTP Semantics」 の §9.2.1 で規定された正式な分類です。セキュリティ的な「安全性」とは別概念で、そのリクエストがサーバー側リソースの状態を変えることを、クライアントが要求も期待もしない(=実質的に読み取り専用である)ことを指します。GET / HEAD / OPTIONS などが safe に該当します。

なお safe なメソッドでも、アクセスログの記録やカウンタの増加といった副作用は起こり得ますが、それらはクライアントが要求した効果ではない、という考え方です。

しかし、クエリが複雑になってくると次のような問題が顔を出します。RFC 10008 の Introduction では、以下の点が明確に挙げられています。

  • サイズ上限が事前に読めない:リクエストは多数の無関係な中継システム(プロキシ、ゲートウェイなど)を通過するため、URI の実際の上限が分からない。RFC 9110 は、最低でも 8000 オクテットのサポートを推奨しているに過ぎません
  • エンコードが非効率:ネストしたフィルタや任意の JSON のような構造化データを、URI に収まる文字列へ押し込むのはコストが高く、可読性も悪くなります
  • ログに残りやすい:リクエスト URI はリクエストボディよりもログに記録されやすく、ブックマークにも現れます。機密を含むクエリでは特に問題になります
  • リソースの爆発:クエリ入力のあらゆる組み合わせが、それぞれ別個のリソース(別 URI)として扱われてしまいます

POST の限界

そこで多くの実装は、「読み取り」であるにもかかわらず POST を使い、条件をボディに載せます。

POST /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded

q=foo&limit=10&sort=-published

ボディを使えるのでサイズやエンコードの問題は解決します。しかし今度は、このリクエストが「安全で冪等な読み取り」であることが、プロトコル上どこにも表現されていないという問題が残ります。POST は状態を変えうるメソッドなので、キャッシュもそのように扱いますし、通信が途中で切れたときに安易にリトライしてよいのかも分かりません。「POST /search なのに実は副作用がない」というのは、サーバーとリソースの個別知識がなければ判断できない、暗黙の約束事にすぎません。

QUERY が埋めるギャップ

QUERY は、この GET と POST の間のギャップを埋めます。POST のようにボディを持てて、GET のように安全・冪等、というハイブリッドです。

QUERY /feed HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded

q=foo&limit=10&sort=-published

見た目は POST とほぼ同じですが、QUERY は明示的に safe かつ idempotent と定義されているため、キャッシュや自動リトライといった機能を安全に適用できます。RFC 10008 の Introduction には、3つのメソッドの性質を並べた分かりやすい比較表が載っています。要点をまとめると次のようになります。

性質 GET QUERY POST
Safe(安全) yes yes 場合による(潜在的に no)
Idempotent(冪等) yes yes 場合による(潜在的に no)
クエリ自体の URI あり(定義上) 任意(Location ヘッダー) なし
クエリ結果の URI 任意(Content-Location 任意(Content-Location 任意(Content-Location
キャッシュ可能 yes yes 将来の GET/HEAD 用に限り yes
ボディの意味 定義された意味なし 期待される(リソース依存) 期待される(リソース依存)

QUERY だけが「ボディを持ちながら、GET と同じ安全・冪等の保証を得られる」列になっている点に注目してください。

QUERY 登場までの歴史

実は「安全かつ冪等で、ボディを持つメソッド」というアイデア自体は新しいものではありません。IANA の HTTP メソッドレジストリには、safe かつ idempotent という性質を持つメソッドが QUERY 以前からすでに3つ存在していました。PROPFINDRFC 4918)、REPORTRFC 3253)、SEARCHRFC 5323)です。

これらを更新して流用することも理論上は可能でした。実際、本仕様の初期段階では SEARCH という名前が使われていました。しかし最終的に「QUERY」が選ばれた理由を、RFC 10008 は付録 B で次のように説明しています。

  • 既存の3メソッドはいずれもリクエストボディに汎用メディアタイプ(application/xml)を前提としており、意味づけがリクエスト内容に強く依存していた
  • そしてこれらはすべて WebDAV 由来であり、WebDAV に対しては複雑な感情を抱く人が多い、という事情がある
  • 「QUERY」という名前は、URI の query コンポーネントとの関係をよく捉えている

WebDAV(Web Distributed Authoring and Versioning、RFC 4918)は、HTTP を拡張して「Web 上のファイルを遠隔で編集・管理する」ための仕組みで、PROPFIND や MKCOL、LOCK といった独自メソッドを多数追加したものです。候補に挙がった3メソッドはいずれもこの系譜から来ています。

ここで「複雑な感情」と言われるのは、WebDAV がメソッドの多さ・XML ベースのボディ・ロック機構などにより重く実装が難しいこと、そして「HTTP の上に XML で何でも乗せる」という当時の思想が、その後の JSON / REST 時代とはやや相性が悪くなったこと、が背景にあります。Windows のネットワークドライブ接続や SharePoint、Subversion などで苦労した記憶を持つ人、いませんか?

とはいえ WebDAV は CalDAV / CardDAV の土台として今も現役であり、RFC も「嫌われている」ではなく「複雑な感情を抱く人が多い」という外交的な表現にとどめています。QUERY が汎用 XML ではなく任意のメディアタイプ(JSON・SQL・JSONPath など)でクエリを書ける設計を選び、名前も WebDAV 系から離して付けたのは、こうした経緯への対比だと読み取れます。

議論の再燃のきっかけもドキュメントに記録されています。この HTTP メソッドに関する議論は、2019年の HTTP Workshop で Asbjørn Ulsberg 氏によって再び持ち上げられました。そこから仕様策定が進み、

  • 2025年11月:最終ドラフト
  • 2025年11月20日:IESG による承認
  • 2026年6月中旬:RFC 10008 として発行

という流れをたどりました。元となったドラフト名は draft-ietf-httpbis-safe-method-w-body(httpbis WG)で、名前がそのまま「ボディを持つ安全なメソッド」という長年のテーマを表しています。HTTP はめったに動きませんが、だからこそ動いたときには注目する価値があります。

QUERY メソッドの使い方

ここからは実際の使い方を、RFC の例を交えながら見ていきます。

基本形

QUERY は「リクエストターゲットに対して、ボディの内容をクエリとして処理させ、その結果を返させる」メソッドです。ボディにクエリを書き、Content-Type でその形式を示します。

QUERY /contacts HTTP/1.1
Host: example.org
Content-Type: application/x-www-form-urlencoded
Accept: application/json

select=surname,givenname,email&limit=10&match="email=*@example.*"

レスポンス例:

HTTP/1.1 200 OK
Content-Type: application/json

[
  { "surname": "Smith", "givenname": "John",
    "email": "smith@example.org" },
  { "surname": "Jones", "givenname": "Sally",
    "email": "sally.jones@example.com" }
]

重要なルールとして、Content-Type が欠けていたり、ボディの内容と矛盾している場合、サーバーはリクエストを失敗させなければなりません(MUST)。メディアタイプが無ければ 400、サポート外なら 415、内容自体が処理できない(例:構文は正しいが存在しないテーブルを指す SQL)なら 422、といった具合にステータスコードの使い分けも規定されています。

クエリ形式は application/x-www-form-urlencoded に限りません。RFC の付録では、SQL(application/sql)や JSONPath(application/jsonpath)、XSLT(application/xslt+xml)を使う例も示されています。「どんな読み取りクエリでも汎用的に載せられる」のが QUERY の狙いです。

Accept-Query で対応形式を調べる

サーバーがどのクエリ形式を受け付けるかは、新しく定義された Accept-Query レスポンスヘッダーで知ることができます。

HEAD /contacts HTTP/1.1
Host: example.org
HTTP/1.1 200 OK
Accept-Query: application/x-www-form-urlencoded, application/sql

Accept-Query は Structured Fields(RFC 9651)の構文で書かれる点に注意してください。見た目は Accept に似ていますが、処理は Structured Field として行う必要があります。なお、QUERY 対応そのものを調べるだけなら、OPTIONS で Allow: GET, QUERY, OPTIONS, HEAD のように返ってくるかを確認する方法もあります。

Structured Fields(Structured Field Values for HTTP、RFC 9651)は、HTTP ヘッダー値の書き方・読み方を統一するための仕様です。

従来のヘッダーはフィールドごとに独自の文法を持ち、空白やクォートの扱いが曖昧で安全にパースしづらいという問題がありました。Structured Fields は、あらかじめ決められた少数のデータ型(トップレベルの List / Dictionary / Item と、Integer・String・Token などの基本型)と、ただ一つの厳密なパース/シリアライズ規則を用意し、共通の処理系で安全に扱えるようにします。

Accept-Query はこのうち List として定義されており、"application/jsonpath", application/sql;charset="UTF-8" のように「Token または String の項目を並べ、各項目にパラメータを付けられる」構造になっています。見た目が似ている Accept は独自文法なので、Accept-Query を同じ感覚でパースしてはいけない、というのが「Structured Field として処理する」の意味です。

クエリや結果を URI 化する(Content-Location / Location)

QUERY の面白いところは、「重要なリソースは URI で識別されるべき」という設計原則に沿って、クエリやその結果に URI を割り当てられる点です。

  • Content-Location:今回の処理結果そのものを表すリソースの URI。以後はそこへ GET すれば同じ結果を取り出せる(一時的な場合あり)。
  • Location:同じクエリを再実行できるリソースの URI。ボディを再送しなくても、そこへ GET すれば最新の結果が得られる。
HTTP/1.1 200 OK
Content-Type: application/json
Content-Location: /contacts/stored-results/17
Location: /contacts/stored-queries/42

これにより、一度 QUERY で投げた重い検索を、次回以降は軽量な GET に切り替えられます。キャッシュや条件付きリクエスト(If-None-Match / If-Modified-Since)とも組み合わせやすくなります。

キャッシュの扱い

QUERY のレスポンスはキャッシュ可能です。ただし GET と決定的に違うのは、キャッシュキーにリクエストボディ(と関連メタデータ)を含めなければならない点です(MUST)。URI だけを見ていた従来のキャッシュとは前提が変わるため、後述の注意点にもつながります。キャッシュ効率のために、コンテンツエンコーディングの除去や、メディアタイプに基づく正規化を行ってよいことになっていますが、これはあくまでキャッシュキー生成のためであり、リクエスト自体は変更しません。

Postman で試す

「仕様は分かったが、手元でどう投げるのか」が気になるところです。2026年8月時点では Postman に QUERY 専用の UI はまだありませんが、Postman は以前からカスタムHTTPメソッドに対応しているので問題ありません。この機能は2018 年末に導入されたもので、標準リストにないメソッド(REPORT や PURGE など)を使えるようにするためのものです。

手順は次のとおりです。

  1. 新しいリクエストタブを開く(New > HTTP、または +)。
  2. メソッドのドロップダウンをクリックし、メソッド名のテキスト欄に QUERY と入力して保存する。これで QUERY が選べるようになります。
  3. URL を入力する(例:https://example.org/contacts)。
  4. Body タブで raw を選び、右側のドロップダウンから形式(JSON など)を選択して、クエリ本文を記述する。この形式を選ぶと、対応する Content-Type ヘッダー(JSON なら application/json)が自動で設定されます。
  5. Send で送信し、レスポンスを確認する。

image.png

例えば JSON でフィルタを送るなら、Body に次のように書きます。

{
  "role": "admin",
  "sort": "name",
  "page": 1
}

ポイントは、QUERY がボディの意味づけを Content-Type に強く依存させる設計だという点です。JSON のように Postman のドロップダウンに用意されている形式であれば、上記のとおり Content-Type は自動で設定されるので、自分で付ける必要はありません。

一方で注意したいのは、RFC の例に出てくる application/jsonpathapplication/sql といった形式は、Postman の Body タブのドロップダウンには用意されていない、という点です。これらで QUERY を投げたい場合は、raw の形式を Text などにしてボディを書いたうえで、Headers タブで Content-Type を手動で application/jsonpathapplication/sql に設定してください。前述のとおり、Content-Type が無い/ボディの内容と矛盾するリクエストはサーバー側で弾かれる規定になっているため、ここは正確に合わせる必要があります。

ブラウザの fetch() や各種フレームワークの対応状況は流動的です。Postman のようなクライアントは任意のメソッドを送れるので、サーバー実装の検証にはうってつけです。

導入時の注意点

QUERY は「正しいプリミティブ」ですが、標準化されたばかりのメソッドである以上、周辺インフラの対応はこれから追いついてくる段階です。すぐに唯一の経路として採用するより、慎重に見極めながら進めるのが現実的です。

  • CORS プリフライトが必要:QUERY は CORS のセーフリスト対象メソッド(GET / HEAD / POST)ではありません。したがってブラウザの JavaScript からクロスオリジンで投げる場合は、事前にプリフライト(OPTIONS)リクエストが発生します。
  • WAF / プロキシ / ロードバランサーの許可リスト:多くの中継装置は GET / POST / PUT / DELETE / PATCH を前提にメソッドの許可リストを書いています。2026年6月より前に書かれたルールは QUERY を想定しておらず、拒否したり POST と違う扱いをしたりする可能性があります
  • キャッシュポイズニングの注意:キャッシュキーにボディを含める必要があるため、ボディの正規化を誤るとキャッシュポイズニングやキャッシュ・デセプションの温床になり得ます
  • フレームワーク・ランタイム対応状況(2026年8月時点):Node.js は 2024 年初頭から QUERY をネイティブにパースでき、OpenAPI 3.2 はドキュメント化に対応しています。Java 方面では、Tomcat が QUERY 対応をマージ済みですが、これは doQuery のディスパッチ経路の追加が Jakarta Servlet API 自体の変更を要するため Tomcat 12 での提供になります。Spring はまだネイティブ対応しておらず(RequestMethod enum に QUERY が無い)、RFC 10008 対応の PR(spring-framework #34993)がレビュー中で、Spring Framework 7.1(2026年11月リリース予定)での導入が見込まれています。それまでの間は RequestMethod.valueOf("QUERY") / HttpMethod.valueOf("QUERY") を使ったつなぎの書き方で対応できます
  • ブラウザ(fetch / XHR)Fetch の仕様上メソッドに制限はないため、fetch(url, { method: "QUERY", body: ... }) は現在のブラウザでもそのまま送信できます。ただし前述のとおり QUERY はセーフリスト対象外なので、クロスオリジンではプリフライトが発生します。むしろ成熟途上なのは、QUERY レスポンスのキャッシュ(キャッシュキーにボディを含める挙動)をブラウザや中継のHTTPスタックがどこまで正しく扱うか、という部分です

現実的な移行パスとしては、既存の POST /search エンドポイントと並行して QUERY を追加し、Accept-Query で対応形式を告知しつつ、クライアント側のツールが対応するのを待って徐々に移行していくのがよいでしょう。

まとめ

QUERY は、「ボディを持てて、なおかつ安全・冪等」という、GET にも POST にもなかった性質を、初めて標準として実現したメソッドです。検索・フィルタ API で長年続いてきた「GET にするか POST にするか」というジレンマに、ようやくプロトコルレベルの答えが用意されました。

とはいえ、標準化はゴールではなくスタートです。サーバー・クライアント・中継装置の実装が出そろい、実際に安心して使えるようになるのは、おおむね2027〜2028年頃と見られています。まずは Postman でカスタムメソッドとして試してみて、Content-TypeAccept-Query、キャッシュの挙動を手を動かして確かめるところから始めるのがよさそうです。16年ぶりの新メソッドが現場に定着していく過程を、リアルタイムで追いかけていきましょう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?