REST APIのベストプラクティス:パラメータをどこに置くか?[閉まっている]


348

REST APIは、少なくとも次の2つの方法でパラメーターを持つことができます。

  1. URLパスの一部として(つまり/api/resource/parametervalue
  2. クエリ引数として(つまり/api/resource?parameter=value

ここでのベストプラクティスは何ですか?1を使用する場合と2を使用する場合の一般的なガイドラインはありますか?

実際の例:Twitterはクエリパラメータを使用して間隔を指定します。(http://api.twitter.com/1/statuses/home_timeline.json?since_id=12345&max_id=54321

これらのパラメーターをURLパスに配置する方が良い設計と見なされますか?

回答:


254

文書化されたベストプラクティスがある場合、私はそれらをまだ見つけていません。ただし、URLのどこにパラメータを配置するかを決定するときに使用するいくつかのガイドラインを次に示します。

オプションのパラメーターは、クエリ文字列に簡単に入力できる傾向があります。

パラメータ値が既存のリソースに対応していないときに404エラーを返したい場合は、パスセグメントパラメータを使用する傾向があります。たとえば/customer/232、232は有効な顧客IDではありません。

ただし、空のリストを返す場合は、パラメーターが見つからないときにクエリ文字列パラメーターを使用することをお勧めします。例えば/contacts?name=dave

パラメータがURIスペースのサブツリー全体に影響する場合は、パスセグメントを使用します。たとえば、言語パラメータ /en/document/foo.txt/document/foo.txt?language=en

クエリパラメータではなく、パスセグメントに固有の識別子を置くことを好みます。

URIの公式ルールは、このRFC仕様にありますここには、URIをパラメータ化するためのルールを定義する、もう1つの非常に役立つRFC仕様があります。


5
公式ルールURIとドラフトsepcは本当に便利で興味深いものでした。:-)
KajMagnus

1
404エラーテストは、クエリパラメータ、ヘッダー、またはリクエストの本文に含まれるパスに情報を入れないようにするのに役立ちます。指摘してくれてありがとう!
Kevin Condon 2014

152

遅い答えですが、共有されているものにいくつかの追加の洞察を追加します。つまり、要求にはいくつかのタイプの「パラメーター」があり、これを考慮に入れる必要があります。

  1. ロケーター-たとえば、IDやアクション/ビューなどのリソース識別子
  2. フィルター-結果セットの検索、並べ替え、または絞り込みを行うパラメーターなど。
  3. 状態-たとえば、セッションID、APIキー、whatevs。
  4. 内容-格納するデータなど。

次に、これらのパラメーターが移動する可能性のあるさまざまな場所を見てみましょう。

  1. リクエストヘッダーとCookie
  2. URLクエリ文字列( "GET"変数)
  3. URLパス
  4. 本文クエリ文字列/マルチパート( "POST"変数)

通常は、状態情報の種類に応じて、ヘッダーまたはCookieに状態を設定します。私たちは皆これに同意できると思います。必要に応じて、カスタムHTTPヘッダー(X-My-Header)を使用します。

同様に、コンテンツには、クエリ本文として、またはhttpマルチパートやJSONコンテンツとして、リクエスト本文に含まれる1つの場所しかありません。これは、コンテンツを送信するときにサーバーから受け取るものと一致します。だから、失礼な態度をとって、違うやり方をするべきではありません。

「id = 5」、「action = refresh」、「page = 2」などのロケーターmysite.com/article/5/page=2は、各部分が何を意味するかを部分的に知っている場所(記事や5は明らかにid 5)のアーティクルタイプのデータを取得することを意味し、追加のパラメーターはURIの一部として指定されます。彼らは、の形態にすることができるpage=2、またはpage/2あなたはURIで特定のポイントの後に「フォルダ」は、キーの値を対になっていることがわかっている場合。

フィルターは常にクエリ文字列に含まれます。フィルターは適切なデータの検索の一部ですが、ロケーターが返すもののサブセットまたは変更を返すためにのみ存在するためです。mysite.com/article/?query=Obama(サブセット)での検索はフィルターであり、/article/5?order=backwards(変更)もフィルターです。それが何と呼ばれるかだけでなく、それが何をするかを考えてください!

「ビュー」が出力形式を決定する場合、それはフィルター(mysite.com/article/5?view=pdf)です。これは、必要なリソースに移動するのではなく、見つかったリソースの変更を返すためです。代わりに、記事のどの特定の部分を表示するかを決定する場合(mysite.com/article/5/view=summary)、ロケーターです。

一連のリソースを絞り込むことはフィルタリングです。リソース内で特定の何かを見つけることは見つけることです... サブセットフィルタリングは、任意の数の結果(0であっても)を返す可能性があります。位置を特定すると、その特定のインスタンス(存在する場合)が常に検出されます。変更フィルタリングは、変更された場合を除いてロケーターと同じデータを返します(変更が許可されている場合)。

これが人々が何かを置く場所について失われた場合に人々にいくつかのユーレカの瞬間を与えるのに役立ったことを願っています!


2
なぜidフィルターではないのですか?これは、リソースのサブセットを返します
ジョナサン。

13
@ジョナサン。いいえ、特定のリソース、つまり記事番号5を返します。フィルターは、常にリソースのコレクション内の検索を絞り込む方法です。その特定のリソースだけが必要な場合は、それを取得するための指定された方法があるはずです。フィルタリングは、複数のリソースを返す可能性があることを意味します。IDはフィルターではなく、明確な単一のリソースです。IDの範囲がある場合、範囲に1つのIDが含まれているだけでも、それはフィルターになります。フィルターにリソースのタイプも含まれている場合、記事だけでなくID 5のすべてのリソースが返されます。
Tor Valamo 2014年

1
@Jonathan .: DarrelMillerが述べたように、idが不明の場合、object / idへのリクエストは404を返すことが期待されますが、object?id = idが返され、リストが空になることが期待されます。また、すべてのタイプのフィルタリング/サブセット化がリストを返す必要があると考えます。
njzk2 14

1
ページは、リソース(ページのコレクション)のフィルターになる可能性があるため難しいものですが、同時に、そのコレクション内の特定のリソースでもあります。私は常にフィルターではなくロケーターによって記事ページをリクエストします。ただし、ページは、ユーザーのリストなど、何かのリストのフィルターにすることができます。しかし、ページは本質的にデリミタであり、別名「アイテム(page-1)*perpageから開始してアイテムを表示perpageする」です。それをフィルターとして使用するのは正しいことですが、理由はさまざまです。「ページ」と呼ぶのは技術的に間違っています。より意味的に正しいのは、「from」または「startAt」と呼ぶことです
Tor Valamo

1
(続き)「ページ」のセマンティックな意味は、変更されない特定のリソースであることです。それは物理的な印刷から来ています。本や印刷物がなかったとしたら、「ページ」は一言にもならないでしょう。「ページ」に分割されたアイテムの動的リストがある場合、数値、アルファベット順、またはアイテム固有の特定の開始点と、「ページあたりの数」フィルターを提供する必要があります。リストにあるものを参照したい場合は、詳細を教えてください。また、私はあなたが今、内部を変更した実現するために、5ページに行きたくないperpage代わりに、20の50に
TorのValamo

21

デザインによります。REST over HTTPでのURIのルールはありません(主なものは一意であることです)。多くの場合、味と直感の問題になります...

私は次のアプローチを取ります:

  • url path-element:リソースとそのpath-elementは、ディレクトリトラバーサルとサブリソースを形成します(例:/ items / {id}、/ users / items)。不明な場合は、そのトラバースと考え、「別のディレクトリ」で考えているかどうかを同僚に尋ねます。最も可能性の高いパス要素は正しい選択です。
  • urlパラメータ:トラバーサルがない場合(複数のクエリパラメータを持つ検索リソースは、そのための非常に良い例です)

1
実際のところ、URIがどのように見えるかについてはかなり明確なルールがあり、それらをRESTful URIに適用する方法についての曖昧さはほとんどありません。
DanMan、2014年

18

IMOパラメータはクエリ引数としてより優れているはずです。URLはリソースを識別するために使用されますが、追加されたクエリパラメータは、リソースのどの部分を必要とするか、リソースが持つべき状態などを指定します。


7
実際には、パスとクエリの両方を組み合わせてリソースを識別します。これはRFC 3986で明確にされました http://labs.apache.org/webarch/uri/rfc/rfc3986.html#query
Darrel Miller

@DarrelMiller私はこれが古い投稿であることを知っていますが、リソースを識別するためにクエリパラメータも使用されているという事実について詳しく知りたいです。あなたが提供したリンクは現在死んでいます。私はRFC3986を見てきましたが、あなたがこの事実をどのように推論したかわかりません。また、定義により、識別子パラメーターはオプションであってはならないため、識別のためにクエリパラメーターを使用するのは適切ではないようです。
Mickael Marrache 2013

@MickaelMarracheセクション3.4 tools.ietf.org/html/rfc3986#section-3.4の
Darrel Miller

2
@DarrelMillerありがとう!私の質問は、一般に、中間HTTPコンポーネントがクエリ文字列を含むリクエストの応答をキャッシュしないという事実から来ています。したがって、クエリパラメータは、リソースを一意に識別するのではなく、いくつかの基準に従ってリソースを検索する方が適しているようです。
Mickael Marrache 2013

17

REST実装に従って、

1)パス変数は、連絡先や曲などのリソースに対する直接アクションに使用されます。例:
GET etc / api / resource / {songid}または
GET etc / api / resource / {contactid}は、それぞれのデータを返します。

2)クエリperms / argumentは、曲のメタデータなどの間接リソースに使用されます。


5
実際にはREST 標準はありません。Wikipediaごと:SOAPベースのWebサービスとは異なり、RESTful Web APIの「公式」標準はありません。[14] これは、RESTがプロトコルであるSOAPとは異なり、アーキテクチャスタイルであるためです。RESTは標準ではありませんが、そのようなウェブなどRESTfulな実装では、HTTPなど、URI、XMLなどの標準を使用することができます
DavidRR

2つのアプローチは好きではありません。/ api / genres?songid = 123または/ api / songs / {song-id} / genresを優先する方がいい
Bart Calixto 2014年

1
@ Bart、Satishはパス内の変数を参照していましたが、これは基本的にユーザーが設定として参照したものです。ただし、ジャンルが実際にはメタデータであり、曲のエンティティ/リソースのフィールドではない場合、私はもっと感性を見ることができました。その上でクエリ文字列を使用して..
ブレット・キャスウェル

@BrettCaswellはそれを得た!指摘してくれてありがとう。心から感謝する!
Bart Calixto 2015年

16

universe-resource-locatorが提供する「コンテキスト」に対してデータを「パック」してPOSTします。これは、ロケーターのために#1を意味します。

#2で制限に注意してください。私は#1よりもPO​​STを好みます。

注:制限については、

POST in POSTパラメータコンテンツの最大サイズはありますか?

GET in GETリクエストの長さに制限はありますか?そして_GETでのURLパラメータの最大サイズ

これらの制限は、クライアントの機能(ブラウザ)とサーバー(構成)に基づいています。


アドオン:ウィッティルートはバージョン(ヘッダーで区別)を持つことができるため、restifyのように記述したrest-full(api)コードを使用するコードを変更する必要なく進化した機能を提供->バージョン付きルートを探す
dgm

5

URI標準によれば、パスは階層パラメーター用であり、クエリは非階層パラメーター用です。Ofc。それはあなたにとって階層的であるものは非常に主観的であることができます。

同じリソースに複数のURIが割り当てられている状況では、パラメーター(識別に必要)をパスに、パラメーター(表現の作成に必要)をクエリに挿入します。(私にとっては、この方法でルーティングする方が簡単です。)

例えば:

  • /users/123 そして /users/123?fields="name, age"
  • /users そして /users?name="John"&age=30

map reduceでは、次のアプローチを使用するのが好きです:

  • /users?name="John"&age=30
  • /users/name:John/age:30

したがって、URIをどのように構築するかは、実際にはユーザー(およびサーバー側ルーター)に任されています。

注:これらのパラメータはクエリパラメータです。したがって、実際に行っているのは、単純なクエリ言語を定義することです。複雑なクエリ(and、or、より大きいなどの演算子を含む)では、既存のクエリ言語を使用することをお勧めします。URIテンプレートの機能は非常に制限されています...


4

多くの場合クライアント側のプログラマーとして、私はクエリ引数を好みます。また、私にとっては、URLパスをパラメーターから分離し、明確さを追加し、拡張性を高めています。また、URL / URIの構築とパラメータービルダーの間で個別のロジックを持つことができます。

ある種の木が含まれている場合、マヌエルアルダナが他のオプションについて言ったことが好きです。ユーザー固有のパーツがそのようにツリー化されているのがわかります。


4

厳密な規則はありませんが、純粋に概念的な観点から使用した経験則は、次のように簡単に要約できます。URIパス(定義により)はリソースを表し、クエリパラメータは基本的にそのリソースの修飾子です。これまでのところ、おそらくヘルプ... REST APIではないことをあなたが使用して単一のリソースに作用するの主要なメソッドを持ってGETPUTDELETE。したがって、パスで何かを表す必要があるのか​​、それともパラメーターとして表す必要があるのか​​を、それらのメソッドが問題の表現にとって意味があるかどうかにまで減らすことができます。PUTその道筋で合理的に何かしますか、そうすることは意味的に健全でしょうか?もちろんPUT、どこかで何かをし、それを処理するためにバックエンドを曲げることもできますが、PUT実際のリソースの表現に相当するものであり、不必要にコンテキスト化されたバージョンではありません。コレクションの場合も、で同じことができますPOST。特定のコレクションに追加したい場合、意味のあるURLは何でしょうかPOST

一部のパスは親リソースの子に相当する可能性があるため、灰色の領域が残っています。これが描く1つの難しい線は、基になるリソースがないため、任意のタイプの推移的な表現はクエリパラメータを使用して実行する必要があるということです。

元の質問(TwitterのAPI)で与えられた実際の例に応じて、パラメーターは(階層ではなく)リソースの状態でフィルター処理する推移的なクエリを表します。その特定の例では、これらの制約によって表されるコレクションに追加することはまったく理不尽であり、さらに、そのクエリは、オブジェクトグラフの観点から意味のあるパスとして表すことができません。

このタイプのリソース指向のパースペクティブを採用すると、ドメインモデルのオブジェクトグラフに簡単に直接マップでき、APIのロジックを、すべてが非常にきれいに機能し、明確になったらかなり自己文書化するようにできます。この概念は、従来のURLルーティングを使用するシステムから、通常は適切でないデータモデル(RDBMSなど)にマッピングすることで、より明確にすることもできます。Apache Slingは、開始するのに適しています。Zopeのようなシステムにおけるオブジェクトトラバーサルディスパッチの概念も、より明確なアナログを提供します。


4

これが私の意見です。

クエリパラメータは、リクエストのメタデータとして使用されます。これらは、既存のリソース呼び出しに対するフィルターまたは修飾子として機能します。

例:

/calendar/2014-08-08/events

その日のカレンダーイベントを提供する必要があります。

特定のカテゴリのイベントが必要な場合

/calendar/2014-08-08/events?category=appointments

または30分以上のイベントが必要な場合

/calendar/2014-08-08/events?duration=30

リトマステストでは、クエリパラメータがなくてもリクエストを処理できるかどうかを確認します。


2

私は一般的に#2をクエリの引数として使用する傾向があります(つまり、/ api / resource?parameter = value)。

3番目のオプションは、body = valueを実際に投稿することです。

これは、マルチパラメータリソースに対してより適切に機能し、将来の使用のために拡張可能であるためです。

どちらを選ぶにせよ、必ず1つだけを選び、混ざり合わないようにしてください。それは混乱するAPIにつながります。


2

このトピックの「ディメンション」の1つは省略されていますが、それは非常に重要です。「ベストプラクティス」が、REST機能で実装または拡張しているプラ​​ットフォームと一致する必要がある場合があります。

実用的な例:

現在、多くのWebアプリケーションがMVC(モデル、ビュー、コントローラー)アーキテクチャーを実装しています。彼らは特定の標準パスが提供されていると想定していますが、それらのWebアプリケーションに「Enable SEO URLs」オプションが付いている場合はさらにそうです。

かなり有名なWebアプリケーションであるOpenCart eコマースショップです。管理者が「SEO URL」を有効にすると、そのURLが次のような非常に標準的なMVC形式であることが期待されます。

http://www.domain.tld/special-offers/list-all?limit=25

どこ

  • special-offers URLを処理するMVCコントローラーです(特別オファーページを表示)

  • list-all呼び出すコントローラーのアクションまたは関数名です。(*)

  • limit = 25はオプションであり、ページごとに25項目が表示されることを示します。

(*)list-allは、わかりやすくするために使用した架空の関数名です。実際には、OpenCartおよびほとんどのMVCフレームワークにはindex、ユーザーがデフォルトのアクションを実行したいときに呼び出されるデフォルトの暗黙の(通常はURLでは省略されている)関数があります。したがって、実際のURLは次のようになります。

http://www.domain.tld/special-offers?limit=25

非常に標準的なアプリケーションまたは上記と同様のフレームワーク構造により、多くの場合、それに最適化され、URLを書き換えるWebサーバーを取得します(真の「非SEOされたURL」は次のようになりますhttp://www.domain.tld/index.php?route=special-offers/list-all&limit=25)。

したがって、開発者は、既存のインフラストラクチャを処理し、「ベストプラクティス」を適用することに直面します。システム管理者でない限り、Apache / NGinxの書き換え構成を微調整する方法を正確に知っています(後者は厄介な場合があります!)。オン。

そのため、REST APIは、参照元のWebアプリケーションの標準に準拠していることがよくあります。これは、REST APIとの一貫性と使いやすさ/速度の両方(したがって予算の節約)の両方を実現します。

上記の実用的な例に戻ると、一貫したREST APIは次のようなURLを持つものになります。

http://www.domain.tld/api/special-offers-list?from=15&limit=25

または(非SEO URL)

http://www.domain.tld/index.php?route=api/special-offers-list?from=15&limit=25

「パスが形成された」引数と「クエリが形成された」引数の組み合わせ。



0

それは非常に興味深い質問です。

両方を使用できますが、この件について厳密な規則はありませんが、URIパス変数を使用するといくつかの利点があります。

  • キャッシュ:インターネット上のほとんどのWebキャッシュサービスは、クエリパラメーターが含まれている場合、GETリクエストをキャッシュしません。サーバーでデータを変更するためにGETリクエストを使用するRPCシステムがたくさんあるので、彼らはそうします(失敗!! Getは安全な方法でなければなりません)

ただし、パス変数を使用する場合、このすべてのサービスでGETリクエストをキャッシュできます。

  • 階層:パス変数は階層を表すことができます:/ City / Street / Place

データの構造に関する詳細情報をユーザーに提供します。

ただし、データに階層関係がない場合でも、コンマまたはセミコロンを使用してPath変数を使用できます。

/ City / longitude、latitude

原則として、パラメーターの順序が重要な場合はコンマを使用し、順序が重要でない場合はセミコロンを使用します。

/ IconGenerator / red; blue; green

これらの理由とは別に、クエリ文字列変数を使用することが非常に一般的な場合があります。

  • ブラウザがHTMLフォーム変数をURIに自動的に配置する必要がある場合
  • アルゴリズムを扱っているとき。たとえば、Googleエンジンはクエリ文字列を使用します。

http:// www.google.com/search?q=rest

要約すると、このメソッドのいずれかを使用する強い理由はありませんが、可能な場合は常にURI変数を使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.