web-dev-qa-db-ja.com

検索はどのようにRESTfulインターフェースに適合しますか?

RESTfulインターフェースを設計する場合、要求タイプのセマンティクスが設計に不可欠であると見なされます。

  • [〜#〜] get [〜#〜]-コレクションのリストまたは要素の取得
  • [〜#〜] put [〜#〜]-コレクションまたは要素を置き換える
  • [〜#〜] post [〜#〜]-コレクションまたは要素を作成します
  • [〜#〜] delete [〜#〜]-えーと、えーと、コレクションまたは要素を削除します

しかし、これは「検索」の概念をカバーしていないようです。

例えば。求人検索サイトをサポートする一連のWebサービスを設計するには、次の要件が必要になる場合があります。

  • 個別の求人広告を取得
    • [〜#〜] get [〜#〜]domain/Job/{id}/
  • 求人広告を作成する
    • [〜#〜] post [〜#〜]からdomain/Job/
  • 求人広告の更新
    • [〜#〜] put [〜#〜]domain/Job/
  • 求人広告の削除
    • [〜#〜] delete [〜#〜]domain/Job/

「Get All Jobs」も簡単です。

  • [〜#〜] get [〜#〜]domain/Jobs/

しかし、仕事の「検索」はどのようにしてこの構造に分類されますか?

あなたはcould「リストコレクション」のバリエーションであると主張し、次のように実装します。

  • [〜#〜] get [〜#〜]domain/Jobs/

ただし、検索canは複雑であり、長いGET文字列を生成する検索を生成することは完全に可能です。つまり、 a SOここに質問 を参照すると、約2000文字を超えるGET文字列を使用すると問題が発生します。

例としては、ファセット検索-「ジョブ」の例の続きがあります。

「テクノロジー」、「職名」、「規律」などのファセット、およびフリーテキストのキーワード、仕事の年齢、場所、給与の検索を許可する場合があります。

流動的なユーザーインターフェイスと多数のテクノロジと役職を使用すると、検索で多数のファセットの選択肢を含めることができます。

この例をジョブではなくCVに微調整すると、さらに多くのファセットがもたらされ、100ファセットが選択された検索や、それぞれが50文字の長さの40ファセット(例:役職、大学名、雇用主名)。

そのような状況では、検索データが正しく送信されるようにするために、PUTまたはPOSTを移動することが望ましい場合があります。例:

  • [〜#〜] post [〜#〜]からdomain/Jobs/

しかし、意味的には、これはコレクションを作成するための指示です。

あなたcouldまた、これを検索の作成として表現するとします。

  • [〜#〜] post [〜#〜]からdomain/Jobs/Search/

または(下記のburninggrammaで示唆されているように)

  • [〜#〜] post [〜#〜]からdomain/JobSearch/

意味的には意味があるように見えるかもしれませんが、実際には何も作成しておらず、データをリクエストしています。

つまり、意味的には[〜#〜] get [〜#〜]ですが、[〜#〜]ですget [〜#〜]が必要なものをサポートするとは限りません。

したがって、問題は-RESTful設計にできる限り忠実に保つことを試み、HTTPの制限内にあることを確認しながら、検索に最も適切な設計は何ですか?

153
Rob Baillie

[〜#〜] get [〜#〜]リクエストには優れた利点があることを忘れないでください他のソリューションより:

1)GETリクエストはURLバーからコピーでき、検索エンジンによってダイジェストされ、「フレンドリー」です。「フレンドリー」とは通常、 GETリクエストは、アプリケーション内の何も変更してはなりません(べき等)。これは、検索の標準的なケースです。

2)これらすべての概念は非常に重要ですユーザーと検索エンジンだけでなく、アーキテクチャ(API)からもデザインの観点。

3)回避策POST/PUTで作成すると、現在考えていない問題たとえば、ブラウザの場合、戻るボタン/ページを更新/履歴。これらはもちろん解決できますが、それは別の回避策、そして次々と...

このすべてを考慮すると、私のアドバイスは次のようになります。

a)GET with内に収まるようにする必要があります巧妙なパラメータ構造。極端なケースでは、 this google search のような戦術を使用することもできます。ここで、多くのパラメーターを設定しますが、それでも非常に短いURLです。

b)アプリケーションに別のエンティティJobSearch。オプションが非常に多いと想定すると、これらの検索も保存して管理する必要があるため、アプリケーションをクリーンアップするだけです。 JobSearchオブジェクト全体をエンティティとして操作できます。つまり、それをテストできます/それを使うeasier


個人的に私はすべての爪でa)でそれを成し遂げるために戦い、すべての希望が失われたとき、私はオプションb)に涙を流しながら戻る

101
p1100i

TL; DR:フィルタリング用のGET、POST検索用

コレクションのリストからの結果のフィルタリングと複雑な検索を区別します。私が使用するリトマステストは基本的に、フィルタリング(正、負、または範囲)以上が必要な場合、POSTを必要とするより複雑な検索だと考えています。

何が返却されるかを考えると、これは強化される傾向があります。通常、リソースのライフサイクルがほぼ完全である場合にのみGETを使用します(PUT、DELETE、GET、コレクションGET)。通常、コレクションGETでは、そのコレクションを構成するRESTリソースであるURIのリストを返します。複雑なクエリでは、応答を構築するために複数のリソースからプルしている場合があります(think SQL join)なので、URIを返送しませんが、実際のデータです。問題は、データがリソースで表現されないことです。そのため、常にデータを返す必要があります。これは、POSTを必要とする明確なケースのようです。

-

久しぶりに元の投稿が少しずさんだったので、更新したいと思った。

GETは、ほとんどの種類のデータ、RESTリソースのコレクション、リソースの構造化データ、単一のペイロード(画像、ドキュメントなど)も含む)を返すための直感的な選択です。

POSTは、GET、PUT、DELETEなどに適合しないように見えるすべてのものに対する包括的な方法です。

この時点で、単純な検索、フィルタリングはGETによって直感的に理解できると思います。複雑な検索は、特に集計関数、相互相関(結合)、再フォーマッターなどをスローする場合、個人の好み次第です。GETパラメーターが長くなりすぎてはならず、クエリが多すぎます(ただし、構造化されています)。 )POST request body。

また、API使用の経験的な側面も考慮します。私は通常、ほとんどの方法を可能な限り使いやすく直感的にしたいと考えています。特に同じAPIの他のRESTリソースの動作と一致しない場合は、POSTに別のリソースURIでより柔軟な(したがってより複雑な)呼び出しをプッシュします。

どちらの方法でも、GETで検索するかPOSTで検索するかよりも、一貫性がおそらくより重要です。

お役に立てれば。

13
dietbuddha

RESTでは、リソース定義はvery幅広いです。ただし、実際にはいくつかのデータをバンドルする必要があります。

  • 検索リソースをコレクションリソースと考えると便利です。クエリパラメータは、URIの検索可能部分と呼ばれることもあり、リソースをクライアントが関心のあるアイテムに絞り込みます。

たとえば、メインのGoogle URIは「インターネット上のすべてのサイトへのリンク」のコレクションリソースを指しています。クエリパラメータは、表示するサイトに絞り込みます。

(URI =ユニバーサルリソース識別子、そのURL =ユニバーサルリソースロケーター、ここではおなじみの "http://"がURIのデフォルト形式です。したがって、URLはロケーターですが、RESTそれをリソース識別子に一般化するのは良いことですが、人々はそれらを交換可能に使用します。

  • この例で検索しているリソースはジョブコレクションであるため、

GET site/jobs?type = blah&location = here&etc = etc

(戻り){ジョブ:[{ジョブ:...}]}

次に、POSTを使用します。これは、追加または処理動詞であり、そのコレクションに新しいアイテムを追加します。

POSTサイト/ジョブ

{ジョブ:...}

  • どちらの場合もjobオブジェクトの構造は同じであることに注意してください。クライアントは、クエリパラメータを使用してジョブのコレクションを取得し、検索を絞り込んでから、アイテムの1つに同じ形式を使用してPOST新しいジョブを実行することができます。または、これらのいずれかを取ることができます。アイテムを更新し、そのURIにPUTして更新します。

  • 非常に長い、または複雑なクエリ文字列の場合、規約により、POSTリクエストとして代わりに送信することができます。クエリパラメータを名前/値ペアとしてバンドルするか、JSONまたはXML構造のネストされたオブジェクトとリクエストの本文で送信します。たとえば、クエリに名前と値のペアではなくネストされたデータがある場合。POSTのHTTP仕様では、追加または処理動詞として説明されています。(RESTの抜け穴から戦艦を航海したい場合は、POSTを使用してください。)

私はそれをフォールバック計画として使用します。

あなたがそれを行うときに失うものはa)GETはnullipotentです-つまり、何も変更しません-POSTは変更しません。したがって、呼び出しが失敗した場合、ミドルウェアは結果を自動的に再試行またはキャッシュします。2)本文に検索パラメーターを指定すると、URIをカットアンドペーストできなくなります。つまり、URIは必要な検索のための特定の識別子ではありません。

「作成」と「検索」を区別するため。 RESTプラクティスと一致するオプションがいくつかあります。

  • コレクションの名前に何かを追加することで、URIでは、求人ではなく求人検索などを行うことができます。これは、検索コレクションを別のリソースとして扱っていることを意味します。

  • POSTのセマンティクスはどちらも追加ORプロセスなので、ペイロードで検索本文を識別できます。{job:...}と{search :...}。適切に投稿または処理するのは、POSTロジック次第です。

これは、ほとんど設計/実装の設定です。明確な慣習はないと思います。

したがって、すでにレイアウトしたように、jobsのコレクションリソースを定義するのが目的です。

サイト/仕事

GET +クエリパラメータで検索して、検索を絞り込みます。長い、または構造化されたデータクエリは、POSTの本体に入る可能性があります(別の検索コレクションへの可能性があります)。POSTで作成して、コレクションに追加します。更新します特定のURIへのPUTで。

(FWIW URIのスタイル規約では、ハイフンで区切られた単語をすべて小文字で使用します。ただし、そのようにする必要はありません。)

(また、あなたの質問から、あなたがこの道を長い道のりを進んでいることは明らかです。それらを並べるために、私は明確に説明しましたが、あなたの質問は、これの意味論的問題のほとんどをすでに扱っていました答え。私は、慣習と慣習を組み合わせただけでした。)

10
Rob

私は通常、ODataクエリを使用します。これらはGET呼び出しとして動作しますが、返されるプロパティを制限してフィルターすることができます。

$select=$filter=などのトークンを使用すると、次のようなURIになります。

/users?$select=Id,Name$filter=endswith(Name, 'Smith')

$skipおよび$topを使用してページングを行い、順序付けすることもできます。

詳細については、 OData.org を参照してください。使用している言語を指定していませんが、ASP.NETの場合、WebApiプラットフォームはODataクエリをサポートしています-他のもの(PHPなど)の場合、それらをデータベースクエリに変換するために使用できるライブラリがおそらくあります。

8
Trevor Pilley

これは古い答えですが、私はまだ議論に少し貢献することができます。 REST、RESTful、およびアーキテクチャーについて誤解していることがよくあります。 RESTfulは検索を構築しないことについては何も言及していません。RESTfulにはアーキテクチャについては何もありません。それは一連の設計原則または基準です。

検索をより適切に説明するには、特にアーキテクチャについて説明する必要があり、より適切なものはリソース指向アーキテクチャ(ROA)です。

RESTfulには設計の原則があります。べき等は、いくつかの回答を読んでも結果が変化しないことを意味するのではなく、独立したリクエストの結果が実行回数に依存しないことを意味します。変更される可能性があります。RESTfulAPIによって提供されるデータをデータベースに供給し続けるデータベースを継続的に更新しているとしましょう。同じGETを実行すると結果が変わる可能性がありますが、実行回数には依存しません。世界を凍結できれば、別の結果につながるリソースを要求したときに、サービス内に状態、変換、その他のものが存在しないことを意味します。

定義上、リソースは、それ自体がモノとして参照されることが重要なものです。

リソース指向アーキテクチャー(簡略化するために、これからROAと呼ぶことにします)では、多くのことが考えられるリソースに焦点を当てます。

  • ドキュメントのバージョン
  • ドキュメントの最終更新バージョン
  • 検索結果
  • オブジェクトのリスト
  • Eコマースから購入した最初の記事

リソースの点でユニークなのはaddresabilityであり、これはRIが1つだけであることを意味します

このようにして、検索ROAを考慮したRESTfulに完全に適合します。 GETを使用する必要があるのは、検索が通常の検索であり、何も変更されないことを前提としているため、べき等です(追加された新しい要素によって異なる結果が返される場合でも)。 ROAではなくRESTfulに固執する可能性があるため、このように混乱しています。ROAのアドレス可能性の原則を使用していないため、検索を作成し、同じパラメーターで異なるものを返すパターンに従うことができます。どう?さて、本文またはヘッダーで検索フィルターを送信すると、リソースはADDRESSABLEではありません。

正確に何であるか、URIの原則はW3の元のドキュメントにあります。

https://www.w3.org/DesignIssues/Axioms

このアーキテクチャのURLはすべて、わかりやすいものにする必要があります。原則に従ってURI内のすべてに対処する必要がある場合は、/(スラッシュ)を使用して必要なものを区切ったり、パラメーターを照会したりできることを意味します。これには制限があることはわかっていますが、これはアーキテクチャパターンです。

RESTfulのROAパターンに従うと、検索は他のどのリソースよりも大きくはありません。唯一の違いは、リソースがオブジェクト自体との直接的な関係ではなく、計算に由来することです。原則に基づいて、次のパターンに基づいて、簡単な算術計算サービスに対処し、取得することができました。

http://myapi.com/sum/1/2

Sum、1、2は変更できますが、計算の結果は一意であり、アドレス指定可能です。同じパラメーターを使用して呼び出すたびに、同じものを取得し、サービスに変更はありません。リソース/ sum/1/2および/ substract/5/4は、原則に完全に準拠しています。

7

検討する1つのアプローチは、可能なクエリのセットをコレクションリソースとして扱うことです。 /jobs/filters

本文にクエリパラメータを指定したこのリソースへのPOSTリクエストは、新しいリソースを作成するか、既存の同等のフィルタを識別して、そのIDを含むURLを返します:/jobs/filters/12345

次に、IDはジョブのGETリクエストで使用できます:/jobs?filter=12345。フィルターリソースに対する後続のGETリクエストは、フィルターの定義を返します。

このアプローチには、フィルター定義のクエリパラメーター形式から解放されるという利点があり、複雑なフィルターを定義するためのより強力な機能を提供する可能性があります。 OR条件は、クエリ文字列では達成が難しいと考えることができる1つの例です。

このアプローチの欠点は、URLの可読性が失われることです(ただし、フィルターリソースのGETリクエストを介して定義を取得することで軽減できる場合があります)。このため、/jobsリソースでも、クエリリソースの同じまたはサブセットをサポートすることをお勧めします。これは、フィルターリソースをサポートする場合と同じです。これは、より短いクエリに使用できます。この機能が提供されている場合、2つのタイプのフィルタリング間のキャッシュ機能を維持するために、/jobsリソースでクエリパラメーターを使用する場合、実装はフィルターリソースを内部で作成/再利用し、302または303ステータスは、/jobs?filter=12345の形式でURLを示します。

5
pgraham

1つのURIに対して常に同じ結果(表現)を返す静的コレクションがある場合、GETは問題ありません。これは、これらの表現を生成するデータが決して変更されないことも意味します。ソースは読み取り専用データベースです。

GETが同じURIに対して異なる結果を返すことは idempotency/safety および CoolURI原則 に違反し、その結果RESTfulではありません。べき等動詞をデータベースに書き込むことは可能ですが、それらが表現に影響を与えることはありません。

一般的な検索は、結果への参照を返すPOSTリクエストで始まります。これは、結果を生成します(それは新しいものであり、後続のGETでフェッチできます)。この結果は階層的(さらにもちろん、GETできるURIでの参照)。アプリケーションにとって意味がある場合は、以前の検索の要素を再利用することもあります。

ちなみに、人によってやり方が違うのは知っています。 RESTに違反することがどれほど便利かを説明する必要はありません。

3