検索用のRESTful URLデザイン


427

検索をRESTfulなURLとして表すための合理的な方法を探しています。

セットアップ:CarsとGaragesという2つのモデルがあり、CarsはGaragesに入れることができます。だから私のURLは次のようになります:

/car/xxxx
  xxx == car id
  returns car with given id

/garage/yyy
  yyy = garage id
  returns garage with given id

車はそれ自体で(つまり/ carとして)存在することも、ガレージ内に存在することもできます。たとえば、特定のガレージ内のすべての車を表す正しい方法は何ですか?何かのようなもの:

/garage/yyy/cars     ?

ガレージyyyとzzzの車の結合についてはどうですか?

特定の属性を持つ車の検索を表す正しい方法は何ですか?説明:4ドアの青いセダンをすべて見せてください。

/car/search?color=blue&type=sedan&doors=4

または、代わりに/ carsにする必要がありますか?

そこでは「検索」の使用が不適切に思われます-より良い方法/用語は何ですか?それだけである必要があります:

/cars/?color=blue&type=sedan&doors=4

検索パラメーターをPATHINFOまたはQUERYSTRINGの一部にする必要がありますか?

つまり、クロスモデルのREST url設計と検索についてのガイダンスを探しています。

[更新]私はジャスティンの答えが好きですが、彼はマルチフィールド検索のケースをカバーしていません:

/cars/color:blue/type:sedan/doors:4

またはそのようなもの。どうやって行くの

/cars/color/blue

複数分野のケースに?


16
英語では見た目はよくなりますが、混合/cars/carあり、意味的ではないため、悪い考えです。そのカテゴリに複数のアイテムがある場合は、常に複数を使用してください。
Zaz

4
これらは悪い答えです。検索にはクエリ文字列を使用する必要があります。クエリ文字列は、適切に(つまり、検索のために)使用すると100%RESTfulになります。
pbreitenbach 2010

回答:


435

検索には、クエリ文字列を使用します。これは完全にRESTfulです。

/cars?color=blue&type=sedan&doors=4

通常のクエリ文字列の利点は、標準で広く理解されており、form-getから生成できることです。


42
これは正しいです。クエリ文字列の要点は、検索などを行うことです。
aehlke 2009

22
RFC3986に従って、パスクエリ文字列がリソースを識別するため、これは実際に正しいです。さらに、適切な名前は単にになります/cars?color=whatever
Lloeki

35
コンパレータ(>、<、<=、> =)が必要な場合はどうですか?/ cars?rating <= 3?
ジェシー

3
クエリ文字列の下にネストされたリソースにアクセスする場合はどうでしょうか?例:/cars?color=blue&type=sedan&doors=4/engines動作しません
阿部Voelker

9
@mjs /cars?param=valueは、車のリストを簡単にフィルタリングする/cars/search?param=valueためのものであり、検索を作成するためのものです(永続化なしでouを使用)。結果には、検索のスコアリング、分類などが含まれる場合があります/cars/search/mysearch。のような名前付き検索を作成/削除することもできます。その時ルック:stackoverflow.com/a/18933902/1480391
イヴ・M.

121

RESTfulなきれいなURL設計は構造に基づいて、リソースを表示する程度である(ディレクトリのような構造、日付:記事/ 2005/5月13日、オブジェクトとそれの属性は、...)、スラッシュは/階層構造を示し、使用-id代わり。

階層構造

私は個人的に好みます:

/garage-id/cars/car-id
/cars/car-id   #for cars not in garages

ユーザーが/car-idパーツを削除すると、carsプレビューが表示されます-直感的。ユーザーはツリーのどこにいるのか、何を見ているのかを正確に知っています。ガレージと車が関係していることを、彼は最初から見て知っています。/car-idまた、とは異なり、一緒に属していることも示し/car/idます。

探す

searchqueryはそのままで問題ありません。ユーザーの好みだけがあり、何を考慮に入れる必要があります。おもしろいのは、検索に参加するときです(下記を参照)。

/cars?color=blue;type=sedan   #most prefered by me
/cars;color-blue+doors-4+type-sedan   #looks good when using car-id
/cars?color=blue&doors=4&type=sedan   #I don't recommend using &*

または基本的に、上記で説明したスラッシュではないもの。
公式:/cars[?;]color[=-:]blue[,;+&]、*。ただし、&一見テキストでは認識できないため、記号は使用しません。

** URIでJSONオブジェクトを渡すことがRESTfulであることをご存知ですか?**

オプションのリスト

/cars?color=black,blue,red;doors=3,5;type=sedan   #most prefered by me
/cars?color:black:blue:red;doors:3:5;type:sedan
/cars?color(black,blue,red);doors(3,5);type(sedan)   #does not look bad at all
/cars?color:(black,blue,red);doors:(3,5);type:sedan   #little difference

可能な機能?

検索文字列を否定する(!)
車を検索するには、 検索しませ
?color=!black,!red
color:(!black,!red)

入社検索は
検索またはまたはと車3つのガレージのIDでドアを1..20または101..103または999しかしない 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
あなたは、より複雑な検索クエリを構築することができます。(CSS3属性の一致を見て、部分文字列を一致させるアイデアを見つけてください。たとえば、「bar」を含むユーザーを検索しますuser*=bar。)

結論

あなたはすべての後のような、しかし、あなたがそれを行うことができますので、とにかく、これはちょうどことを覚えておいて、あなたのために最も重要な部分であるかもしれないRESTfulな URIが簡単などのようなディレクトリ・理解されている構造で表し/directory/file/collection/node/item日付、/articles/{year}/{month}/{day}...とするとき、あなたを省略最後のセグメントのどれでも、何が得られるかすぐにわかります。

したがって、これらすべての文字はエンコードれていないこと許可されます。

  • 予約なし:a-zA-Z0-9_.-~
    通常、エンコードと非エンコードの両方が許可され、両方の使用は同等になります。
  • 特殊文字: $-_.+!*'(),
  • 予約済み:;/?:@=&
    それらが表す目的でエンコードされていない状態で使用できます。それ以外の場合はエンコードする必要があります。
  • unsafe:<>"#%{}|\^~[]`
    なぜ安全ではなく、なぜエンコードする必要があるのか​​:RFC 1738 2.2を参照

    その他の文字クラスについては、RFC 1738#page-20も参照してください。

RFC 3986は2.2を参照
以前に述べたことにも関わらず、デリミタの一般的な違いは次のとおりです。つまり、一部は他よりも重要」であることが重要です。

  • 一般的な区切り文字: :/?#[]@
  • サブデリメータ: !$&'()*+,;=

参考資料
階層:2.3参照、1.2.3を参照
URLパスパラメータ構文
CSS3属性が
IBM:RESTful Webサービスに一致-基本事項
注:RFC 1738はRFC 3986によって更新されました


3
クエリ文字列でJSONを使用することを考えたことがないと思います。それは私が直面していた問題への答えです-を使用しない複雑な検索構造POST。また、あなたの回答で与えた他のアイデアも非常に高く評価されます。どうもありがとう!
gustavohenke 2013年

4
@Qwerty:素晴らしい投稿!私は疑問に思いました:;反対に使用する唯一の理由&は読みやすさですか?もしそうなら、私は&それがより一般的な区切り文字なので正しいと思います...そうですか?:)ありがとう!
Flo 2015

3
@Floはい、正確に:)ですが&、区切り文字としては開発者だけが知っていることに注意してください。両親、祖父母、および教育を受けていない人々は、一般的な書面で使用されている区切り文字を受け入れます。
Qwerty、2015

17
クエリ文字列がよく理解され、標準であるのに、なぜ非標準のスキームを構成するのですか
pbreitenbach

1
/ search?cars = red、blue、green&garages = 1,2,3からあなたを止める@Qwerty何もない、または<multiselect>フォームを使用する場合:/ search?cars = red&cars = blue&
garages

36

パスにパラメーターがあることにはいくつかの利点がありますが、IMOにはいくつかの重要な要素があります。

  • 検索クエリに必要なすべての文字がURLで許可されるわけではありません。ほとんどの句読点とUnicode文字は、クエリ文字列パラメータとしてURLエンコードする必要があります。私は同じ問題に取り組んでいます。URLでXPathを使用したいのですが、すべてのXPath構文がURIパスと互換性があるわけではありません。したがって、単純なパスの場合/cars/doors/driver/lock/combinationcombination、運転席ドアのXMLドキュメントで' '要素を見つけることが適切です。しかし/car/doors[id='driver' and lock/combination='1234']、それほど友好的ではありません。

  • 属性の1つに基づいてリソースをフィルタリングすることと、リソースを指定することには違いがあります。

    たとえば、

    /cars/colors すべての車のすべての色のリストを返します(返されるリソースは色オブジェクトのコレクションです)

    /cars/colors/red,blue,green 車のコレクションではなく、赤、青、緑のカラーオブジェクトのリストを返します。

    車を返すには、パスは

    /cars?color=red,blue,green または /cars/search?color=red,blue,green

  • 名前と値のペアは、名前と値のペアではないパスの残りの部分から分離されていないため、パスのパラメーターは読みにくくなります。

最後のコメント。単数形と複数形の間のパスの変更を回避するため、(おそらく元の回答ではタイプミスであった/garages/yyy/cars)よりも(常に複数形)を好み/garage/yyy/carsます。「s」が追加された単語の場合、変更はそれほど悪くありませんが、に変更/person/yyy/friendsするの/people/yyyは面倒です。


2
はい、同意します... URLのパス構造はエンティティ間の自然な関係を反映する必要があります。ガレージには多くの車があり、車はガレージに属しているなど、リソースのある種のマップは...フィルターパラメーターを使用して、クエリ文字列をクエリします...どう思いますか?
opensas、2009年

31

ピーターの答えを拡張するには、検索を一流のリソースにすることができます。

POST    /searches          # create a new search
GET     /searches          # list all searches (admin)
GET     /searches/{id}     # show the results of a previously-run search
DELETE  /searches/{id}     # delete a search (admin)

検索リソースには、色、モデルの作成、ガレージステータスなどのフィールドがあり、XML、JSON、またはその他の形式で指定できます。車とガレージのリソースと同様に、認証に基づいて検索へのアクセスを制限できます。同じ検索を頻繁に実行するユーザーは、プロファイルをプロファイルに保存できるため、再作成する必要がありません。URLは十分に短いため、多くの場合、電子メールで簡単に取引できます。これらの保存された検索は、カスタムRSSフィードなどの基礎となります。

リソースとして考える場合、検索を使用する可能性はたくさんあります。

このRailscastでアイデアについて詳しく説明します。


6
このアプローチは、落ち着きのないプロトコルで作業するという考えに反しませんか?つまり、データベースへの検索を永続化することは、一種のステートフルな接続を持っていることです...そうではありませんか?
opensas、2009年

5
ステートフルなサービスを提供するようなものです。また、新しい車やガレージを追加するたびにサービスの状態を変更しています。検索は、HTTP動詞の全範囲で使用できるもう1つのリソースです。
リッチアポダカ

2
上記はどのようにURI規約を定義していますか?
リッチアポダカ

3
RESTは、綺麗なURIやURIの入れ子などとは何の関係もありません。URIをAPIの一部として定義した場合、それはRESTではありません。
aehlke 2009

2
これについては以前に議論しました。これは決してステートフルではありませんが、ひどいことです。検索の「削除」は完全には明確ではありません。ここでは、この検索エンティティを削除すると言っていますが、それを使用して、その検索で見つけた結果を削除したいと思います。リソースとして「検索」を追加しないでください。
thecoshman 2014年

12

Justinの答えはおそらく進むべき道ですが、アプリケーションによっては、特定の検索をそれ自体をリソースと見なすことが理にかなっている場合があります。

/search/{searchQuery}

または

/search/{savedSearchName}

11
番号。アクションをリソースにしても意味がありません。
thecoshman 2014年

3
@thecoshman上記のコメントで述べたように、検索も名詞です。
andho

6

私は2つのアプローチを使用して検索を実装します。

1)関連付けられた要素を照会し、ナビゲーションするための最も単純なケース。

    /cars?q.garage.id.eq=1

つまり、ガレージIDが1の自動車をクエリします。

より複雑な検索を作成することも可能です:

    /cars?q.garage.street.eq=FirstStreet&q.color.ne=red&offset=300&max=100

赤ではないFirstStreetのすべてのガレージ内の車(3ページ目、ページあたり100要素)。

2)複雑なクエリは、作成され、回復できる通常のリソースと見なされます。

    POST /searches  => Create
    GET  /searches/1  => Recover search
    GET  /searches/1?offset=300&max=100  => pagination in search

検索作成用のPOST本文は次のとおりです。

    {  
       "$class":"test.Car",
       "$q":{
          "$eq" : { "color" : "red" },
          "garage" : {
             "$ne" : { "street" : "FirstStreet" }
          }
       }
    }

Grailsに基づいています(基準DSL):http : //grails.org/doc/2.4.3/ref/Domain%20Classes/createCriteria.html


5

これはRESTではありません。API内でリソースのURIを定義することはできません。リソースナビゲーションはハイパーテキスト駆動である必要があります。かなりのURIと大量の結合が必要な場合は問題ありませんが、RESTfulアーキテクチャの制約に直接違反するため、RESTと呼ばないでください。

RESTの発明者によるこの記事を参照してください。


28
RESTではなく、RESTfulシステムのURL設計です。ただし、RESTfulアーキテクチャに違反していると言うのも誤りです。RESTのハイパーテキスト制約は、RESTfulシステムの適切なURL設計と直交しています。私が数年前にRESTリストでRoy T. Fieldingと話し合ったとき、私が彼が明示的に述べた場所に参加したことを覚えています。別の言い方をすれば、ハイパーテキストとURLのデザインを持つことが可能です。RESTfulシステムのURL設計は、プログラミングにおけるインデントのようなものです。必須ではありませんが、非常に良いアイデアです(Pythonを無視するなど)
MikeSchinkel 2010

2
すみません、あなたは正しいです。OPから、URLの作成方法をクライアントに認識させるという印象を受けました。彼は、APIの一部としてURLの「レイアウト」を作成します。それはRESTの違反になります。
aehlke 2010

@aehlke、コメントと一致するように回答を更新する必要があります。
James McMahon

1
レベル2のRichardson成熟度モデルに準拠しています。あなたはレベル3を参照しています。RESTを徐々に採用できるものとして受け入れてください。
Jules Randolph

1
@Jules Randolph-申し訳ありませんが、私の回答は、Richardson成熟度モデルが最初に作成されてから数か月後、Martin Fowlerや他の著者がそれを普及する前に書かれました:)実際、これは参考になるモデルです。回答を自由に編集してください。
aehlke

1

私はジャスティンの応答が好きですが、検索よりもフィルターをより正確に表すと感じています。camで始まる名前の車について知りたい場合はどうすればよいですか?

私の見たところ、特定のリソースを処理する方法に組み込むことができます:
/ cars / cam *

または、単にフィルターに追加することができます:
/ cars / doors / 4 / name / cam * / colors / red、青、緑

個人的には後者を好みますが、私は決してRESTの専門家ではありません(2週間ほど前に初めて聞いた...)


このように:/cars?name=cam*
DanMan

1

RESTfulは、URLの/ cars / searchで動詞を使用することをお勧めしません。APIをフィルター/検索/ページ分割する正しい方法は、クエリパラメーターを使用することです。ただし、規範を破る必要がある場合もあります。たとえば、複数のリソースを検索する場合、/ search?q = queryのようなものを使用する必要があります

http://saipraveenblog.wordpress.com/2014/09/29/rest-api-best-practices/参照して、RESTful APIを設計するためのベストプラクティスを理解することができます。


1
検索は😀すぎ名詞である
jith912

1

さらに、私もお勧めします:

/cars/search/all{?color,model,year}
/cars/search/by-parameters{?color,model,year}
/cars/search/by-vendor{?vendor}

ここでSearchは、Carsリソースの子リソースと見なされます。


1

ここにあなたのケースに適したオプションがたくさんあります。それでも、POSTボディの使用を検討する必要があります。

クエリ文字列はこの例に最適ですが、たとえばアイテムの任意の長いリストやブール条件など、より複雑なものがある場合、クライアントがPOSTで送信するドキュメントとして投稿を定義することができます。

これにより、より柔軟な検索の説明が可能になり、サーバーのURLの長さの制限を回避できます。


-4

私のアドバイスはこれでしょう:

/garages
  Returns list of garages (think JSON array here)
/garages/yyy
  Returns specific garage
/garage/yyy/cars
  Returns list of cars in garage
/garages/cars
  Returns list of all cars in all garages (may not be practical of course)
/cars
  Returns list of all cars
/cars/xxx
  Returns specific car
/cars/colors
  Returns lists of all posible colors for cars
/cars/colors/red,blue,green
  Returns list of cars of the specific colors (yes commas are allowed :) )

編集:

/cars/colors/red,blue,green/doors/2
  Returns list of all red,blue, and green cars with 2 doors.
/cars/type/hatchback,coupe/colors/red,blue,green/
  Same idea as the above but a lil more intuitive.
/cars/colors/red,blue,green/doors/two-door,four-door
  All cars that are red, blue, green and have either two or four doors.

うまくいけば、それはあなたにアイデアを与えます。基本的に、Rest APIは簡単に発見でき、データを参照できるようにする必要があります。クエリ文字列ではなくURLを使用するもう1つの利点は、HTTPトラフィック用にWebサーバー上に存在するネイティブキャッシュメカニズムを利用できることです。

RESTでのクエリ文字列の悪を説明するページへのリンクは次のとおりです。http//web.archive.org/web/20070815111413/http//rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful

通常のページが機能しなかったため、Googleのキャッシュを使用しました。ここにもリンクがあります。http//rest.blueoxen.net/cgi-bin/wiki.pl?QueryStringsConsideredHarmful


1
詳細な回答ありがとうございます。最後に、色とドアの数の両方で検索したい場合はどうすればよいですか?/ cars / colors / red、blue、green / doors / 4それは正しくないようです。
Parand

2
URL内のカンマは私には適切ではないと思われますが、それでも有効な残りの部分です。それは単なるパラダイムシフトだと思います。
ジャスティンボゾニア2008年

21
この提案は好きではありません。/cars/colors/red,blue,greenとの違いをどのように知ってい/cars/colors/green,blue,redますか?URIのパス要素は階層的である必要がありますが、ここではそうではありません。これは、クエリ文字列が最も適切な選択である状況だと思います。
troelskn 2009年

62
これは悪い答えです。実際、検索を実装する適切な方法は、クエリ文字列を使用することです。クエリ文字列は、適切に使用すれば、少しも邪魔になりません。引用された記事は検索に言及していません。提供されている例は明らかに拷問を受けており、さらに多くのパラメーターを使用しても十分に対応できません。
pbreitenbach 2010

4
クエリ文字列は主に、複数のパラメータを使用した場合でも、リソースのクエリの問題を解決するために作成されました。「RESTful」APIを有効にするためにURIを変換するのは危険で近視眼的です-特に、URIのパラメーターのさまざまな置換を処理するためだけに独自の複雑なマッピングを記述する必要があるためです。さらに良いことに、URIにセミコロンを使用するという既存の概念を使用してください。doriantaylor.com
Anatoly G
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.