web-dev-qa-db-ja.com

クエリパラメータの長いリストを使用してRESTfulクエリAPIを設計する

いくつかのフィルターに基づいて一連のオブジェクトを返すRESTfulクエリAPIを設計する必要があります。このための通常のHTTPメソッドはGETです。唯一の問題は、少なくとも12個のフィルターを持つことができ、それらすべてをクエリパラメーターとして渡すと、URLが非常に長くなる可能性があることです(ファイアウォールによってブロックされるのに十分な長さ)。

パラメータの数を減らすことはオプションではありません。

考えられる代替案の1つは、URIでPOSTメソッドを使用し、POST本文の一部としてフィルターを送信することです。これは、RESTfull(POSTを呼び出してデータを照会すること)に反対ですか?.

誰より良いデザインの提案がありますか?

129
missionE46

REST AP​​Iを使用する場合、それはすべてあなたの観点の問題であることを忘れないでください。

REST AP​​Iの2つの重要な概念は、エンドポイントとリソース(エンティティ)です。端的に言えば、エンドポイントはGETを介してリソースを返すか、POSTおよびPUTなど(または上記の組み合わせ)を介してリソースを受け入れます。

POSTを使用すると、送信するデータによって、新しいリソースとそれに関連するエンドポイントが作成される場合とされない場合があります。言い換えると、POSTを処理するためにどこかにデータを送信します。 POSTエンドポイントは、通常リソースが見つかる場所ではありません。

RFC 2616 からの引用(無関係な部分は省略し、関連する部分を強調表示):

9.5 POST

POSTメソッドは、リクエストに含まれるエンティティを、Request-LineのRequest-URIで識別されるリソースの新しい部下として受け入れるように要求するために使用されます。 POSTは、次の機能をカバーする統一されたメソッドを許可するように設計されています。

  • ...
  • フォームの送信結果などのデータブロックをデータ処理プロセスに提供する;
  • ...

...

POSTメソッドによって実行されるアクションは、URIで識別できるリソースにならない場合があります。この場合、応答に結果を説明するエンティティが含まれているかどうかに応じて、200(OK)または204(No Content)が適切な応答ステータスです

Originサーバーでリソースが作成されている場合、応答は201(作成済み)である必要があります...

問題ドメインが指示するものは何でも、ユーザー、メッセージ、書籍など、「モノ」または「データ」を表すエンドポイントおよびリソースに慣れてきました。ただし、エンドポイントは、検索結果などの別のリソースを公開することもできます。

次の例を考えてみましょう。

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

これは典型的なREST CRUDです。ただし、追加した場合:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

このエンドポイントについて、RESTfulなものはありません。要求本文の形式でデータ(エンティティ)を受け入れます。そのデータはSearch Criteria-他のようなDTOです。このエンドポイントは、リクエストへの応答でリソース(エンティティ)を生成します:Search Results。検索結果リソースは一時的なものであり、リダイレクトせずに、他の正規URLから公開されることなく、すぐにクライアントに提供されます。

エンティティがブックではないことを除いて、RESTです。リクエストエンティティはブック検索条件であり、レスポンスエンティティはブック検索結果です。

110
Amir Abiri

クエリ文字列が長すぎるか複雑すぎる(たとえば、クエリ文字列がネストされたデータを簡単に処理できない)GETを代わりにPOSTとして送信できるという慣行を受け入れています。リクエストの本文で表される長いデータ。

HTTP仕様でPOSTの仕様を検索します。それは信じられないほど広いです。 (RESTの抜け穴から戦艦を航海したい場合は、POSTを使用します。)

GETはi等であるため、自動再試行のようなGETセマンティクスの利点の一部を失いますが、それで耐えることができれば、POSTで本当に長いまたは複雑なクエリの処理を受け入れる方が簡単かもしれません。

(笑長い余談...最近、HTTP仕様でGET canにドキュメント本文が含まれていることを発見しました。言い換えると、「リストされたもの以外のすべてのリクエストはドキュメント本文を持つことができます」このセクションでは...」と、それが参照するセクションにはリストがありません。HTTP作成者がそれについて話しているスレッドを検索して見つけました。これは意図的であり、ルーターなどは区別する必要がありません。ただし、実際には多くのインフラストラクチャの断片がGETの本文をドロップします。したがって、POSTのように本文で表されるフィルターを使用してGETできますが、サイコロを転がすことになります。

72
Rob

簡単に言うと、POSTを作成しますが、X-HTTP-Method-Overrideヘッダーを使用してHTTPメソッドをオーバーライドします。

実際のリクエスト

POST /書籍

エンティティ本体

{「タイトル」:「イプサム」、「年」:2017}

ヘッダー

X-HTTP-Method-Override:GET

サーバー側で、ヘッダーX-HTTP-Method-Overrideが存在するかどうかを確認し、バックエンドの最終エンドポイントへのルートを構築するメソッドとしてその値を取得します。また、エンティティ本体をクエリ文字列として使用します。バックエンドの観点から見ると、リクエストは単なるGETになりました。

このようにして、デザインをREST原則と調和させます。

編集:このソリューションは、元々一部のブラウザやサーバーでPATCH動詞の問題を解決することを意図したものでしたが、非常に長いURLの場合はGET動詞でも動作します。質問。

6
Delmo