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


153

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

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

私が考えることができる1つの代替案は、URIでPOSTメソッドを利用し、POSTボディの一部としてフィルターを送信することです。これはRESTfull(クエリデータへのPOST呼び出しを行う)に対するものですか?

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


2
短い(1文字​​など)パラメータ名を使用しますか?
Madbreaks 2013年

2
本当にRESTfulではないかもしれませんが、GETとPOSTに関しては実用的である必要があると思います。送信する変数がたくさんあり、それらを減らすことができない場合は、それらをPOSTします。URLを詰め込みすぎたくないのですが、それは私だけです。
Doug Dawson

ありがとう。この質問は締め切られましたが、それはまさに私が答えを必要とした質問です。ご質問いただきありがとうございます。
Casey Crookston、

回答:


142

REST APIの場合、それはすべてあなたの視点の問題であることを覚えておいてください。

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

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

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

9.5投稿

POSTメソッドを使用して、オリジンサーバーがリクエストに含まれるエンティティを、Request-LineのRequest-URIで識別されるリソースの新しい下位として受け入れることをリクエストします。POSTは、以下の機能をカバーする統一された方法を可能にするように設計されています。

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

...

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

オリジンサーバーでリソースが作成されている場合、応答は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なものはありません。リクエストボディの形式でデータ(エンティティ)を受け入れます。そのデータは、他のようなDTOである検索基準です。このエンドポイントは、リクエスト(検索結果)に応答してリソース(エンティティ)を生成します。検索結果リソースは一時的なものであり、リダイレクトなしで、また他の正規URLから公開されることなく、クライアントにすぐに提供されます。

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


DTOのいくつかのクラス命名規則を提案できますか?
Kwadz 16

個人的に私は行くだろうBooksSearchCriteriaDTOBooksSearchResultsDTO
Amir Abiri、2016

このPOST / books / searchの場合に最適なHTTP応答コードは何ですか?201はまだ適用されますか?
L. Holanda 2017

9
201は反対です-リソースが作成されたことを意味します。どこかに固有のURIを持つことが期待されるリソース。201はPOSTCRUDのC部分に使用する場合に適しています。私は普通の古い200を使用しますが、オプションで空の検索結果用にオプションで204を使用することもできます。
アミールアビリ2017

@AmirAbiriありがとうございます。
mohamed-mhiri

84

多くの人々は、クエリ文字列が長すぎる、または複雑すぎる(たとえば、クエリ文字列はネストされたデータを簡単に処理できない)GETは、本体に複雑な/長いデータが表現されたPOSTとして送信できるという慣習を受け入れていますリクエストの。

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

GETはべき等であるため、自動再試行のようなGETセマンティクスの利点の一部を失いますが、それに耐えることができれば、POSTで非常に長いクエリや複雑なクエリの処理を受け入れる方が簡単な場合があります。

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


11
本文付きのHTTP GETについて詳しくは、この質問もご覧ください。
RickyA 2013

6

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

実際のリクエスト

POST / books

エンティティボディ

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

ヘッダー

X-HTTP-Method-Override:GET

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

このようにして、RESTの原則と調和した設計を維持します。

編集:私はこのソリューションが元々一部のブラウザーとサーバーでのPATCH動詞の問題を解決することを目的としていたことを知っていますが、質問で説明されている問題である非常に長いURLの場合、GET動詞で私のためにも機能します。


2
IETFは非推奨のX接頭辞付きHTTPヘッダー:tools.ietf.org/html/rfc6648
jannis


@jannisリンクするRFCは1.4のままです。既存のX-削除と1.5 については推奨しません 。既存の仕様を上書きすることはありません。... X-IMOはここに残ります。
Jan Molnar

-3

JavaとJAX-RSで開発している場合は、@ GETで@QueryParamを使用することをお勧めします

リストを調べる必要があるときにも同じ質問がありました。

例を参照してください:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

URIパターン:「poc / test?code = 1&code = 2&code = 3

@QueryParamは、クエリパラメータ“ orderBy = age&orderBy = name”をjava.util.Listに自動的に変換します。


あなたの例を説明するともっといいでしょう。それはどのプログラミング言語で書かれていますか?
Aleks Andreev

こんにちは@AleksAndreev。ご意見ありがとうございます。良くなった?tks
acacio.martins

この質問は、RESTfulサービスの設計に関するものであり、実装に関するものではありません。この答えは質問には答えません。
異端者の猿、

@ user1331413 IMHOはい、今はより良いです。努力ありがとうございます。しかし、Mike McCaughanが言ったように、質問は実装ではなくRESTの概念についてです
Aleks Andreev
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.