HN 日本語サマリー

← 一覧へ戻る
Web開発

新しいHTTP QUERYメソッドの解説

The new HTTP QUERY method explained (kreya.app)

21 pointsby CommonGuy3 コメント

要約

新しいHTTP QUERYメソッドは、RFC 10008で定義されたHTTPメソッドであり、複雑なクエリにおけるGETリクエストの限界と、読み取り専用操作にPOSTを使用する際のセマンティックな問題を解決するために導入されました。このメソッドはGETに似ていますが、リクエストボディを許可し、セーフかつ冪等であり、キャッシュ可能です。複雑な検索クエリに最適なソリューションを提供しますが、まだサポートは限定的であるため、導入前には現在のサポート状況とユースケースを慎重に検討する必要があります。

全文翻訳

RESTful APIの世界では、私たちは長年にわたり厳格な(自らに課した)ルールに従ってきました。GETでデータを取得する場合でも、POSTでエンティティを作成する場合でも、PUTでリソースを更新する場合でも、HTTPメソッドはサーバーに意図を伝えます。ごく最近、HTTPの新しいQUERYメソッドを定義するRFC 10008が公開されました。既存の他のHTTPメソッドがあるのに、なぜこれが必要なのでしょうか?見ていきましょう。 純粋に技術的な観点から見ると、HTTPメソッドは単なる文字列です。理論的には、GET /api/v1/usersを送信する代わりに、FETCH /api/v1/usersを使用することもできます。実際には、GETやPOSTといったよく知られたHTTPメソッドには、多くのRFCや暗黙的で文書化されていない振る舞いがあります。例えば、ブラウザはアドレスを入力したりブックマークをクリックしたりするとGETリクエストを送信します。標準のHTTPフォームはGETとPOSTのみをメソッドとして許可しています。ほとんどのプロキシ、ファイアウォール、ウェブサーバーも「標準」のHTTPメソッドのみを許可しています。では、何十年も機能してきた既存のメソッドがあるのに、なぜ新しいHTTPメソッドを導入するのでしょうか? GETを使用したクエリ 従来、リソースをフィルタリングしたい場合、GETリクエストのクエリパラメータを使用しました(例:/api/v1/users?role=admin&status=active&sort=desc)。これは単純なフィルタにはうまく機能します。しかし、複雑なリレーショナルクエリ、深いネスト、または高度なロジックを実行する必要がある場合、URLは巨大になり、読みにくく、時にはブラウザやサーバーの文字数制限に達することもあります。その他の潜在的な問題には以下が含まれます。 非ASCII文字や特殊文字をパラメータとして送信するにはエンコードが必要であり、リクエストサイズが増大します サーバーやその他のミドルウェアはリクエストパラメータをログに記録する可能性があり、特定の状況では問題となることがあります 配列のような一部のデータ構造の表現は明確に定義されておらず、実装に依存します(例:?roles[0]=admin&roles[1]=reporter vs ?roles=admin&roles=reporter vs ?roles[]=admin&roles[]=reporter) 深いネスト構造の表現も同様です これらすべてがクエリパラメータとしてデータを送信する際の欠点であるため、JSONリクエストボディを持つGETリクエストを単に送信しないのはなぜでしょうか?繰り返しますが、理論的な観点からは、これは機能するはずです。どのHTTP RFCも、HTTP GETリクエストを実行する際にリクエストボディの使用を明示的に禁止してはいませんが、そうすべきではないことを示唆しています。結果として、様々なクライアント、プロキシ、ウェブサーバーの実装では、ボディ付きのGETリクエストの処理が異なります。一部はそれを完全に拒否し、一部は単にボディを破棄し、また一部はそれを解釈します。このため、リクエストボディ付きのHTTP GETを使用することは悪いアイデアです。例えば、企業ファイアウォールの背後にいるユーザーや異なるブラウザを使用しているユーザーがウェブサイトを利用できなくなる可能性があります。既存の多くの実装を壊すことになるため、GETリクエストがリクエストボディをサポートすべきだと規定する新しいRFCがないのもこの理由です。 回避策:POSTを使用したクエリ GETを使用してリクエストボディを送信すると問題が生じる可能性があるため、回避策はPOSTを使用することです。POSTはリクエストボディを許可しますが、重大なセマンティックな問題を引き起こします。POSTは非冪等(non-idempotent)と定義されており、リソースの作成または処理を意図しています。これは大きな問題には聞こえないかもしれませんが、例えば失敗時の自動リトライを実装する際には厄介になることがあります。GETメソッドはセーフかつ冪等(idempotent)と定義されているため、サーバーの実装が正しければ、副作用を心配することなく失敗したリクエストを再試行できます。また、プロキシや他のミドルウェアが操作が読み取り専用であることを自動的に理解することも不可能になります。例えば、ミドルウェアはGETリクエストを一定期間自動的にキャッシュすることがありますが、これはPOSTリクエストでは機能しません。 QUERYメソッド 上記のすべての理由により、長年の議論を経てQUERYメソッドが規定されました。QUERYメソッドは特別なものではなく、RFCではGETメソッドに似ているが、リクエストボディを持つと大まかに述べられています。これはセーフかつ冪等であることを意図しています。QUERYリクエストはキャッシュ可能ですが、実装はリクエストコンテンツをキャッシュキーに組み込むように注意する必要があります。結局のところ、複雑な検索クエリにようやく適切なHTTPメソッドが提供されたことになります。 QUERYの注意点 すべての検索関連エンドポイントをすぐにQUERYに切り替えたくなるかもしれません。しかし、そうする前に考慮すべき点がいくつかあります。HTTP QUERYのサポートはまだ非常に限定的であり、しばらく続く可能性があります。あらゆる場所で完全にサポートされるまでには何年もかかるかもしれません。例えば、Kreyaは最近の1.20リリースでHTTP QUERYの標準サポートを追加しました(ただし、以前からカスタムHTTPメソッドを送信することは可能でした)。他のクライアント、プロキシ、ウェブサーバーは依然としてそれを拒否するかもしれません。URLパラメータにデータを持つ標準のGETクエリは依然として全く問題ありません。それらをQUERYメソッドに変更する差し迫った必要がないのであれば、そのままにしておきましょう。ユーザーがフィルターされたデータのリンクを共有したりブックマークしたりできるようにすべき場合は、引き続きGETリクエストを使用してください。QUERYリクエストとしてのリンク共有は機能しません。QUERYリクエストのカスタムキャッシュを実装することは、リクエストボディを考慮する必要があるため、GETリクエストよりも困難です。 結論 要するに、HTTP QUERYは読み取り専用リクエストにおけるPOSTの代わりになります。それがすべての場所で完全にサポートされるまでには時間がかかるかもしれませんが、通常のGETリクエストではユースケースに不十分な場合は、依然としてそれを検討(そしてテスト!)すべきです。