RESTfulな方法でリソースのサーバー側メソッドを呼び出す


142

RESTについて初歩的な理解があることを覚えておいてください。私がこのURLを持っているとしましょう:

http://api.animals.com/v1/dogs/1/

そして今、私はサーバーに犬の鳴き声をさせたいと思います。サーバーだけがこれを行う方法を知っています。残りの永遠のために犬を10分ごとに吠えるCRONジョブで実行したいとします。その呼び出しはどのように見えますか?私はこれをやりたいと思っています:

URLリクエスト:

ACTION http://api.animals.com/v1/dogs/1/

リクエストの本文:

{"action":"bark"}

独自のHTTPメソッドを作成することに夢中になる前に、私を助けて、RESTfulな方法でサーバー側メソッドを呼び出す方法についてより良いアイデアを教えてください。:)

明確化のために編集

「樹皮」メソッドの機能について、さらに説明します。異なる構造のAPI呼び出しが発生する可能性のあるいくつかのオプションを次に示します。

  1. barkはdog.emailにメールを送信し、何も記録しません。
  2. barkはdog.emailにメールを送信し、dog.barkCountを1ずつ増分します。
  3. barkは、吠え声が発生したときにbark.timestamp記録で新しい「吠え声」レコードを作成します。また、dog.barkCountを1増やします。
  4. barkはシステムコマンドを実行して、最新バージョンの犬のコードをGithubから取得します。次に、dog.ownerにテキストメッセージを送信して、新しい犬のコードが生産中であることを伝えます。

14
興味深いことに、バウンティを追加すると、当初よりも悪い回答が集まったようです;-)回答を評価するときは、次の点に注意してください。1)HTTP動詞の仕様では、POST以外の選択ができません。2)RESTはURL構造とは何の関係もありません–利点(スケーラビリティ、信頼性、可視性など)よりも制約(ステートレス、キャッシュ可能、階層化、統一されたインターフェイスなど)の一般的なリストです。3)現在の慣行(RPC仕様でPOSTを使用するなど)は、独自のAPIルールを作成している定義主義者に勝るものです。4)RESTには(HTTP仕様に準拠した)統一されたインターフェースが必要です。
レイモンドヘッティンガー2013年

@カーク新しい答えについてどう思いますか?あなたがまだ知りたいが、それらのいずれかで対処されなかったものはありますか?役立つと思われる場合は、回答をもう一度編集させていただきます。
ジョーダン

@RaymondHettinger PATCHが適切です。私の答えの終わりの方にある理由を説明します
ジョーダン

PATCHは、dog.barkCountを1 だけ増やす場合にのみ適切です。POSTは、電子メールの送信、新しい樹皮レコードの作成、Githubからダウンロードするコマンドの実行、またはテキストメッセージのトリガーを行う方法です。@ジョーダン、あなたのPATCH RFCの読みは想像力に富んでいますが、部分的なリソース変更のためのPUTの変種としての意図とは少し矛盾しています。リモートプロシージャコールにPOSTを使用する標準的な方法を認めるのではなく、HTTP仕様の型破りな読み方を考え出すことでOPを支援しているとは思いません。
レイモンドヘッティンガー2013年

その練習@RaymondHettinger デファクト標準化POST?私が見たすべての標準RPCインターフェースはエンティティを(RESTfulではなく)リソースとURIで識別しているため、RPC規約を優先する有効な回答は従来とは異なり、従来のRPCの価値を否定するものである必要があります。 。あなたは行くことはできません間違っている、それはキャッチオールデータ処理のためのようPOSTではなく、より具体的な方法があります。RESTは、リソースに名前を付け、その状態の変化を記述することを意味します。PATCHとPOSTはどちらも状態の変化を表します。
ジョーダン

回答:


280

RESTfulなデザインを目指すのはなぜですか?

RESTfulの原則は、Webサイトをランダムな人間のユーザーが「サーフィン」するために)簡単にする機能をWebサービスAPI設計もたらし、プログラマーが簡単に使用できるようにします。RESTはRESTであるため、RESTは適切ではありません。そして、それはシンプルなので、それは主に良いです。

一部の人が「機能の欠如」と呼ぶかもしれないプレーンなHTTP(SOAPエンベロープと単一のURIオーバーロードPOSTサービスなし)の単純さは、実際にはその最大の強みです。すぐに、HTTPはアドレス可能性ステートレス性を要求します。今日のメガサイト(およびメガサービス)までHTTPをスケーラブルに保つための2つの基本的な設計決定です。

しかし、RESTはシルバーバルテットではありません。RPC スタイル(「リモートプロシージャコール」-SOAP など)が適切な場合もあれば、他のニーズがWebの利点よりも優先される場合もあります。これで結構です。私たちが本当に嫌いなのは、不必要な複雑さです。プログラマーや会社がRPCスタイルのサービスを取り入れて、昔ながらのHTTPでうまく処理できることが多すぎます。その効果は、HTTPが、「実際に」何が行われているのかを説明する巨大なXMLペイロードのトランスポートプロトコルに削減されることです(URIまたはHTTPメソッドはそれについての手がかりを与えません)。結果のサービスは非常に複雑で、デバッグが不可能であり、クライアントが開発者が意図したとおりに正確に設定されていないと機能しません。

同様に、Java / C#コードをオブジェクト指向にすることできません。HTTPを使用するだけではデザインはRESTfulになりません。呼び出す必要があるアクションとリモートメソッドの観点から、サービスについて考えるのが急がれる場合があります。これがRPCスタイルのサービス(またはREST-RPCハイブリッド)で終わるのも不思議ではありません。最初のステップは、別の考え方をすることです。RESTfulな設計はさまざまな方法で実現できます。1つの方法は、アクションではなくリソースの観点からアプリケーション考えることです。

it実行できるアクションについて考えるのではなく(「地図上の場所を検索してください」)...

... これらのアクションの結果(「検索条件に一致するマップ上の場所のリスト」)を考慮してください。

以下の例に行きます。(RESTのその他の重要な側面はHATEOASの使用です。ここではそれについては触れませんが、別の投稿ですぐに説明ます。)


最初のデザインの問題

提案されたデザインを見てみましょう:

ACTION http://api.animals.com/v1/dogs/1/

まず、新しいHTTP動詞ACTION)の作成を検討する必要はありません。一般的に、これはいくつかの理由で望ましくありません

  • (1)サービスURIのみが与えられた場合、「ランダム」なプログラマーはACTION動詞が存在することをどのようにして知るでしょうか?
  • (2)プログラマがそれが存在することを知っている場合、プログラマはそのセマンティクスをどのようにして知るのでしょうか?その動詞はどういう意味ですか?
  • (3)その動詞が持つと期待できる特性(安全性、べき等)はどれですか。
  • (4)プログラマーが標準のHTTP動詞のみを処理する非常に単純なクライアントを持っている場合はどうなりますか?
  • (5) ...

次に、使用を検討してPOSTみましょう(以下でその理由を説明します。今、私の言葉を引き受けてください)。

POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com

{"action":"bark"}

これは問題ないかもしれませんが、次の場合のみです

  • {"action":"bark"}ドキュメントでした。そして
  • /v1/dogs/1/「ドキュメントプロセッサ」(工場のような)URIでした。「ドキュメントプロセッサ」とは、「物を投げる」だけで「忘れる」URIのことです。「スロー」した後、プロセッサが新しく作成したリソースにリダイレクトする場合があります。たとえば、メッセージブローカーサービスでメッセージを投稿するためのURI。投稿後、メッセージの処理のステータスを示すURIにリダイレクトされます。

私はあなたのシステムについてはあまり知りませんが、私はすでに両方が真実ではないと確信しています:

  • {"action":"bark"} はドキュメントはありません。実際に、サービスに忍者で忍び込む方法です。そして
  • /v1/dogs/1/URIは、「犬」のリソース(とおそらく犬表しid==1)とないドキュメントプロセッサを。

つまり、上記のデザインはそれほどRESTfulではないということですが、正確には何ですか?何がそんなに悪いのですか?基本的に、それは複雑な意味を持つ複雑なURIであるため、良くありません。それから何も推測できません。プログラマーは、犬barkに秘密裏に注入できるアクションがあることをどのようにして知るでしょうPOSTか?


質問のAPI呼び出しの設計

それでは、追跡に切り替わり、リソースの観点から考えてそれらの樹皮をRESTfulに設計してみましょう。Restful Web Servicesの本を引用させてください。

POSTリクエストは既存のものから新しいリソースを作成しようとする試みです。既存のリソースは、データ構造の意味で新しいリソースの親である場合があります。つまり、ツリーのルートは、そのすべてのリーフノードの親です。または、既存のリソースは、 他のリソースを生成することを唯一の目的とする特別な「工場」リソースである場合があります。POSTリクエストとともに送信される表現は、新しいリソースの初期状態を示します。PUTと同様に、POSTリクエストに表現を含める必要はまったくありません。

上記の説明に従うbarkと、がaのサブリソースdogとしてモデル化できることがわかります(a barkは犬に含まれているため、つまり、吠え声は犬によって「吠えている」ため)。

その理由から、私たちはすでに得ました:

  • メソッドは POST
  • リソースは/barks、「工場」を/v1/dogs/1/barks表すdog:のサブリソースですbark。そのURIは犬ごとに一意です(それがの下にあるため/v1/dogs/{id})。

これで、リストの各ケースに特定の動作があります。

1.樹皮は単に電子メールを送信し、dog.email何も記録しません。

まず、吠えている(電子メールを送信している)のは同期タスクですか、それとも非同期タスクですか?第2に、barkリクエストにはドキュメント(電子メールなど)が必要ですか、それとも空ですか?


1.1 barkが電子メールを送信し、dog.email何も記録しない(同期タスクとして)

このケースは簡単です。barksファクトリリソースを呼び出すとすぐに鳴き声(電子メールが送信されます)が生成され、応答(すぐにOKかどうか)がすぐに示されます。

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(entity-body is empty - or, if you require a **document**, place it here)

200 OK

何も記録(変更)しないので200 OK十分です。すべてが期待どおりに進んだことを示しています。


1.2 barkは電子メールを送信し、dog.email何も記録しません(非同期タスクとして)

この場合、クライアントにはbarkタスクを追跡する方法が必要です。その場合、barkタスクは独自のURIを持つリソースである必要があります。

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed;
NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
to the newly created resource (bark) URI, the same returned in the Location header
(also notice that, for the 202 status code, the Location header meaning is not
standardized, thus the importance of a hipertext/hyperlink response)}

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

このように、それぞれbarkが追跡可能です。次に、クライアントGETbarkURIにを発行して、現在の状態を知ることができます。多分それDELETEをキャンセルするためにa を使用することさえ。


2. barkが電子メールを送信し、1 dog.emailずつ増加dog.barkCountする

これは、dogリソースが変更されたことをクライアントに通知したい場合は、よりトリッキーになる可能性があります。

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

{document body, if needed; when possible, containing a hipertext/hyperlink with the address
in the Location header -- says the standard}

303 See Other
Location: http://api.animals.com/v1/dogs/1

この場合、locationヘッダーの目的は、クライアントにを確認する必要があることを通知することですdog。以下からのHTTP RFCについて303

このメソッドは主に、POSTアクティブ化されたスクリプトの出力がユーザーエージェントを選択したリソースにリダイレクトできるようにするために存在 します。

タスクが非同期の場合、シチュエーションとbark同様にサブリソースが必要であり、タスクが完了したときにが返されます。1.2303GET .../barks/Y


3.樹皮は、樹皮が発生したときにbark記録した新しい「」レコードを作成しますbark.timestamp。またdog.barkCount、1 ずつ増加します。

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

201 Created
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

ここではbark、リクエストによりが作成されているため、ステータス201 Createdが適用されます。

作成が非同期の場合、代わりに202 AcceptedHTTP RFCが言うように)が必要です。

保存されたタイムスタンプはbarkリソースの一部でありGET、それを使用して取得できます。更新された犬GET dogs/X/barks/Yも同様に「文書化」できます。


4. barkがシステムコマンドを実行して、最新バージョンの犬のコードをGithubから取得します。次にdog.owner、新しい犬のコードが生産中であることを伝えるテキストメッセージを送信します。

これの表現は複雑ですが、ほとんどの場合、単純な非同期タスクです。

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

202 Accepted
Location: http://api.animals.com/v1/dogs/1/barks/a65h44

次に、クライアントはGETsを発行し/v1/dogs/1/barks/a65h44て現在の状態を確認します(コードがプルされた場合は、所有者などに電子メールが送信されます)。犬が変わるたびに、a 303が適用されます。


まとめ

ロイ・フィールディングの引用:

RESTがメソッドに必要とする唯一のことは、すべてのリソースに対してそれらが均一に定義されることです(つまり、仲介者がリクエストの意味を理解するためにリソースタイプを知る必要がないようにします)。

上記の例でPOSTは、は均一に設計されています。犬「bark」になります。これは安全ではありません(つまり、樹皮がリソースに影響を与えることを意味しますbarkPOST

プログラマが知っているだろう:A POSTbarks収穫bark。応答ステータスコード(必要に応じてエンティティボディとヘッダーも使用)は、何が変更されたか、およびクライアントがどのようにして続行できるかを説明する役割を果たします。

注:使用された主なソースは、「Restful Web Services」の本、HTTP RFC、およびRoy Fieldingのブログです。




編集:

質問とその答えは、最初に作成されてからかなり変わりました。元の質問は、のようなURIの設計についての質問しました:

ACTION http://api.animals.com/v1/dogs/1/?action=bark

以下は、それが適切な選択ではない理由の説明です。

クライアントは、サーバー言うどのように何をすべきかをデータではあるメソッド情報

  • RESTful Webサービスは、メソッド情報をHTTPメソッドで伝達します。
  • 典型的なRPCスタイルとSOAPサービスは、それらをエンティティ本体とHTTPヘッダーに保持します。

どの部分のデータの上で動作させることである[クライアントがサーバが欲しい] スコープ情報

  • RESTfulサービスはURIを使用します。SOAP / RPCスタイルのサービスは、エンティティボディとHTTPヘッダーを再び使用します。

例として、GoogleのURIを取り上げますhttp://www.google.com/search?q=DOG。そこでは、メソッド情報GETとスコープ情報があり/search?q=DOGます。

短い話:

  • RESTfulなアーキテクチャー、メソッド情報は、HTTPメソッドに入ります。
  • では、リソース指向アーキテクチャ、スコープ情報がURIになります。

そして経験則:

HTTPメソッドがメソッド情報と一致しない場合、サービスはRESTfulではありません。スコーピング情報がURIにない場合、サービスはリソース指向ではありません。

あなたは置くことができ、「樹皮」 「アクション」の URL(またはエンティティボディで)と使用中POST。そこに問題はありません、それは機能し、それを行う最も簡単な方法かもしれませんが、これはRESTfulではありません

サービスを本当にRESTfulに保つには、一歩下がって、ここで本当に何をしたいか(リソースにどのような影響があるか)を考える必要があるかもしれません。

特定のビジネスニーズについてお話しすることはできませんが、例を挙げましょうexample.com/order/123。注文がのようなURIで行われるRESTful注文サービスについて考えてみましょう。

注文をキャンセルしたいとしましょう。どうすればよいでしょうか?それを「キャンセル」 「アクション」であると考え、それをのように設計したくなるかもしれませんPOST example.com/order/123?do=cancel

上で述べたように、それはRESTfulではありません。代わりに、に送信された要素PUTを使用して、の新しい表現を作成できます。ordercanceledtrue

PUT /order/123 HTTP/1.1
Content-Type: application/xml

<order id="123">
    <customer id="89987">...</customer>
    <canceled>true</canceled>
    ...
</order>

以上です。注文をキャンセルできない場合は、特定のステータスコードを返すことができます。POST /order/123/canceledentity-bodyのようなサブリソース設計trueも、簡単にするために利用できる場合があります。)

特定のシナリオでは、同様のことを試すことができます。そのようにして、例えば犬が吠えている間、GETat /v1/dogs/1/はその情報(例えば<barking>true</barking>)を含むことができます。または...それが複雑すぎる場合は、RESTful要件を緩めてに固執しPOSTます。

更新:

答えを大きくしすぎたくはありませんが、アルゴリズム(アクション)をリソースのセットとして公開することにこだわるにはしばらく時間がかかります。アクション(「マップ上の場所を検索する」)の観点から考える代わりに、そのアクションの結果(「検索基準に一致するマップ上の場所のリスト)の観点から考える必要があります。

デザインがHTTPの統一インターフェースに適合しない場合は、この手順に戻る可能性があります。

クエリ変数 スコープ情報です、新しいリソースを示すものではありません/post?lang=en明らかにと同じリソースであり/post?lang=jp、表現が異なるだけです)。むしろ、これらはクライアントの状態?page=10サーバーの状態がサーバーに保持されないように、?lang=enここでも例です)または入力パラメーターアルゴリズムのリソース/search?q=dogs/dogs?code=1)に伝えるために使用されます。繰り返しますが、個別のリソースではありません。

HTTP動詞(メソッド)プロパティ:

?action=somethingURIでRESTfulでないことを示すもう1つの明確な点は、HTTP動詞のプロパティです。

  • GETそしてHEAD安全です(そしてべき等です);
  • PUTそしてDELETE唯一の冪等です。
  • POST どちらでもありません。

安全性GETor HEAD要求は、データを読み取るための要求であり、サーバーの状態を変更するための要求ではありません。クライアントはGETまたはをHEAD10回作成でき、1回作成するのと同じか、まったく作成しないのと同じです。

べき等:1回でも2回以上適用しても同じ効果を持つ1 つのべき等演算(数学では、ゼロを掛けることはべき等です)。DELETEリソースを1度使用した場合、再度削除しても同じ効果があります(リソースはGONE既に存在しています)。

POST安全でもべき等でもありません。POST「ファクトリ」リソースに対して2つの同一のリクエストを行うと、おそらく2つの下位リソースに同じ情報が含まれます。オーバーロード(URIまたはエンティティ本体のメソッド)を使用するとPOST、すべてのベットが無効になります。

これらのプロパティは両方とも、HTTPプロトコルの成功(信頼性のないネットワーク上で!)にとって重要でした。GETページが完全に読み込まれるまで待たずに、ページを何回更新()しましたか?

アクションを作成してURLに配置すると、HTTPメソッドのコントラクトが明らかに破られます。繰り返しますが、このテクノロジーにより可能になりますが、それは可能ですが、それはRESTfulな設計ではありません。


私は、URLでアクションとして指定されているサーバーでアクションを呼び出すことはRESTfulではないという考えに異議を唱えます。 「データのブロックをデータ処理プロセスに提供する」POSTために設計されました。多くの人がリソースとアクションを区別しているようですが、実際にはアクションは単なるリソースの一種です。
Jacob Stevens

1
@JacobStevens OPが質問を少し変更したので、答えを更新してもっと直接的なものにしなければなりません(元の質問を確認してください。多分私の意味がわかるでしょう)。POST「データのブロックをデータ処理プロセスに提供する」ことに同意しますが、実際の違いは、データのブロックではなく、データのブロックと手順(アクション、メソッド、コマンド)その時に実行されました。それはPOSTオーバーロードであり、POSTオーバーロードはRESTfulではなくRPCスタイルの設計です。
acdcjunior 2013年

アクション/メソッドロジックはサーバーに格納されていると思いますが、それ以外の呼び出しの目的は何ですか?あなたが説明する場合、私は同意します、それは良いデザインではないでしょう。しかし、アクションを実行するメソッドまたはサブルーチンは、URIによって指定されます(URLの末尾に動詞として指定されたアクションリソースが有用でRESTfulであるもう1つの理由ですが、多くの人はそれに対して助言します)。
Jacob Stevens

6
回答を更新しました。完全な説明が必要と思われたため、少し長くなっています(「RESTの基本的な理解があることを覚えておいてください」)。それを可能な限り明確にすることは、ある種の闘争でした。それが何らかの形で役立つことを願っています。
acdcjunior 2013年

2
素晴らしい説明、私は投票しましたが、202 Accepted応答ではLocationヘッダーを使用しないでください。多くの人々がRFCから行うのは間違った解釈のようです。このstackoverflow.com/questions/26199228/…を
Delmo

6

は以前回答しましたが、この回答は以前の回答とは矛盾し、解決策にたどり着くための非常に異なる戦略に従います。RESTとHTTPを定義する概念からHTTPリクエストがどのように構築されるかを示しています。またはのPATCH代わりにも使用します。POSTPUT

それは、REST制約、HTTPのコンポーネント、そして考えられる解決策を通過します。

残り

RESTは、分散型ハイパーメディアシステムを拡張可能にするために適用することを目的とした一連の制約です。アクションをリモートで制御するコンテキストでそれを理解する場合でも、リモートでアクションを制御することは、分散ハイパーメディアシステムの一部、つまり相互接続された情報を検出、表示、および変更するためのシステムの一部と考える必要があります。それが価値があるよりも問題がある場合は、RESTfulにしようとすることはおそらく意味がありません。ポート80を介してサーバー上でアクションをトリガーできる「コントロールパネル」タイプのGUIがクライアントに必要な場合は、おそらく、HTTP要求/応答またはWebSocketを介したJSON-RPCのような単純なRPCインターフェースが必要です。

しかし、RESTは魅力的な考え方であり、問​​題の例はたまたまRESTfulインターフェースでモデル化するのが簡単なので、楽しみと教育に挑戦してみましょう。

RESTは、4つのインターフェース制約によって定義されます。

リソースの識別; 表現によるリソースの操作; 自己記述的メッセージ; アプリケーション状態のエンジンとしてのハイパーメディア。

あるコンピュータが別のコンピュータに犬の鳴き声を作るように指示することにより、これらの制約を満たすインターフェースを定義する方法を尋ねます。具体的には、インターフェースをHTTPにし、意図したとおりに使用した場合にHTTP RESTfulにする機能を破棄したくない場合。

最初の制約であるリソース識別から始めましょう。

名前を付けることができる情報はすべてリソースにすることができます:ドキュメントまたは画像、一時的なサービス(「ロサンゼルスの今日の天気」など)、その他のリソースのコレクション、非仮想オブジェクト(個人など)など。 。

だから犬は資源です。識別する必要があります。

より正確には、リソースRは時間的に変化するメンバーシップ関数M Rt)であり、時間tの場合、等価なエンティティのセットまたは値にマップされます。セット内の値は、リソース表現および/またはリソース識別子である場合があります。

あなたは、モデル識別子と表現の集合を取り、彼らはすべての与えられた時間に相互に関連付けられていると言って犬を。ここでは、識別子「dog#1」を使用します。これにより、リソースの表現自己記述という2番目と3番目の制約に移動します。

RESTコンポーネントは、表現を使用してそのリソースの現在または意図された状態をキャプチャし、コンポーネント間でその表現を転送することにより、リソースに対してアクションを実行します。表現は、一連のバイトと、それらのバイトを説明する表現メタデータです。

以下は、犬の意図した状態、つまり識別子「dog#1」に関連付けたい表現をキャプチャする一連のバイトです(犬の名前、健康状態は考慮しないため、状態の一部のみを表すことに注意してください) 、または過去の樹皮):

この状態変更が行われた時から10分ごとに吠え、無期限に継続します。

それを説明するメタデータに添付されることになっています。このメタデータは役に立つかもしれません:

英語の発言です。意図した状態の一部について説明します。それが複数回受信された場合、最初の効果のみを許可します。

最後に、4番目の制約であるHATEOASを見てみましょう。

REST ...は、アプリケーションを情報のまとまりのある構造と見なし、ユーザーが目的のタスクを実行できる代替手段を制御します。たとえば、オンライン博物館で単語を検索するのは1つのアプリケーションであり、仮想博物館を巡回したり、クラスのノートのセットを調べて試験に備えたりするのと同じです。...アプリケーションの次の制御状態は、最初に要求されたリソースの表現に存在するため、最初の表現を取得することが優先されます。...したがって、モデルアプリケーションは、現在の表現セットの代替状態遷移を調べて選択することにより、ある状態から次の状態に移動するエンジンです。

RESTfulインターフェースでは、クライアントはリソース表現を受信して​​、表現を受信または送信する方法を理解します。アプリケーション内のどこかに表現がなければなりません。クライアントは、情報のチェーンをたどってその情報に到達したとしても、受信または送信できるすべての表現を受信または送信する方法を理解できます。これは十分に簡単なようです:

クライアントは、ホームページとして識別されたリソースの表現を要求します。応答として、クライアントが望むすべての犬の識別子を含む表現を取得します。クライアントはそこから識別子を抽出し、識別された犬とどのように相互作用できるかをサービスに尋ねます。サービスは、クライアントが犬の意図した状態の一部を説明する英語のステートメントを送信できると言います。次に、クライアントはそのようなステートメントを送信し、成功メッセージまたはエラーメッセージを受信します。

HTTP

HTTPはREST制約を次のように実装します。

リソース識別:URI

リソースの表現:エンティティ本体

自己記述:メソッドまたはステータスコード、ヘッダー、およびエンティティ本体の一部(例:XMLスキーマのURI)

HATEOAS:ハイパーリンク

http://api.animals.com/v1/dogs/1URIとして決定しました。クライアントがサイトのいくつかのページからこれを取得したとしましょう。

このエンティティ本体を使用してみましょう(値nextはタイムスタンプです。値0は「このリクエストが受信されたとき」を意味します):

{"barks": {"next": 0, "frequency": 10}}

次に、メソッドが必要です。PATCHは、私たちが決定した「意図した状態の一部」の説明に適合します。

PATCHメソッドは、要求エンティティに記述されている一連の変更を、Request-URIで識別されるリソースに適用することを要求します。

そしていくつかのヘッダー:

エンティティ本体の言語を示すには: Content-Type: application/json

一度だけ発生することを確認するには: If-Unmodified-Since: <date/time this was first sent>

そして、私たちは要求を持っています:

PATCH /v1/dogs/1/ HTTP/1.1
Host: api.animals.com
Content-Type: application/json
If-Unmodified-Since: <date/time this was first sent>
[other headers]

{"barks": {"next": 0, "frequency": 10}}

成功すると、クライアントが受け取るべき204応答のステータスコードを、または205の表現があれば/v1/dogs/1/新しい吠えスケジュールを反映するように変更しました。

失敗する403と、理由と役立つメッセージを受け取ります。

RESTがサービスに対して樹皮スケジュールをに応じた表現に反映することは必須ではありませんGET /v1/dogs/1/が、JSON表現にこれが含まれている場合が最も理にかなっています。

"barks": {
    "previous": [x_1, x_2, ..., x_n],
    "next": x_n,
    "frequency": 10
}

cronジョブは、サーバーがインターフェースから非表示にする実装の詳細として扱います。それが一般的なインターフェースの美しさです。クライアントは、サーバーが舞台裏で何をするかを知る必要はありません。サービスが気にするのは、サービスが要求された状態の変化を理解してそれに応答することだけです。


3

ほとんどの人がこの目的でPOSTを使用します。「他のHTTPメソッドが適切と思われないときに、安全でない、またはべき等ではない操作」を実行するのに適しています。

XMLRPCなどのAPI はPOSTを使用して、任意のコードを実行できるアクションをトリガーします。「アクション」はPOSTデータに含まれています。

POST /RPC2 HTTP/1.0
User-Agent: Frontier/5.1.2 (WinNT)
Host: betty.userland.com
Content-Type: text/xml
Content-length: 181

<?xml version="1.0"?>
<methodCall>
   <methodName>examples.getStateName</methodName>
   <params>
      <param>
         <value><i4>41</i4></value>
         </param>
      </params>
   </methodCall>

RPCの例は、POSTがサーバー側メソッドのHTTP動詞の従来の選択であることを示しています。POSTについてロイフィールディングの考えを以下に示します。彼は、指定されたHTTPメソッドを使用することがRESTfulであると言っています。

RPC自体はリソース指向ではないため、RESTfulとは言えません。しかし、ステートレス、キャッシング、またはレイヤー化が必要な場合、適切な変換を行うことは難しくありません。例については、http://blog.perfectapi.com/2012/opinionated-rpc-apis-vs-restful-apis/を参照してください。


パラメータをクエリ文字列に
含め

@カークはい、ただし1つの小さな変更を加えて、最後のスラッシュを削除します。– POST api.animals.com/v1/dogs1?action=bark
レイモンドヘッティンガー

この回答のアドバイスに従う場合は、結果のAPIがRESTfulにならないことに注意してください。
ニコラスシャンクス2013年

2
これはRESTfulなではありませんので、 HTTPは、リソースの識別子とのURLとしてURLを確立/RPC2リソースを識別するために何もしませんが-それは、サーバ技術を識別します。代わりに、これはmethodName「リソース」を「識別」しようとするために使用されますが、それでも、名詞/動詞の区別から利益を得ることはありません。ここでの唯一の「動詞」のようなものはmethodCallです。これは、「状態名を取得する」の代わりに「状態名を取得する」に似ています-後者の方がはるかに理にかなっています。
ジョーダン

リンクの+1。非常に有益で、「意見のあるRPC」実験は進歩的です。
ジョーダン

2

POSTのために設計されたHTTPメソッドです

データブロックをデータ処理プロセスに提供する

CRUDにマップされていないアクションを処理するサーバー側のメソッドは、Roy FieldingがRESTで意図したものであり、それで十分です。それが、POSTべき等ではないように作られた理由です。POST情報を処理するサーバー側メソッドへのほとんどのデータの投稿を処理します。

とはいえ、犬吠えのシナリオで、サーバー側の鳴き声を10分ごとに実行したいが、何らかの理由でトリガーをクライアントから発信する必要がある場合は、べきPUT等性があるため、目的が適切に機能します。まあ、このシナリオでは厳密に言うと、複数のPOSTリクエストが犬の鳴き声を引き起こすという明らかなリスクはありませんが、とにかくそれが2つの類似した方法の目的です。同様のSOの質問に対する私の答えはあなたに役立つかもしれません。


1
PUT対POSTはすべてURLに関するものです。9.6 PUTの後の3番目の段落では、2つのメソッドの目的は、PUTURL がクライアントのコンテンツで置き換えられるものを参照し、URL がクライアントのコンテンツをPOST必要に応じて処理するものを参照することであると述べています。
ジョーダン

1

Barkingが、コンシューマーが作用できる内部/依存/サブリソースであると仮定すると、次のように言うことができます。

POST http://api.animals.com/v1/dogs/1/bark

犬番号1の吠え声

GET http://api.animals.com/v1/dogs/1/bark

最後の樹皮のタイムスタンプを返します

DELETE http://api.animals.com/v1/dogs/1/bark

適用されません!無視してください。


これは、それ自体がリソースであり、そのリソースの内部状態がどのように変化するかを説明/v1/dogs/1/barkする場合にのみRESTfulです。リソースと見なして、それが吠えるべきであることをエンティティ本体で示すことは、より理にかなっています。POST/v1/dogs/1/
ジョーダン

うーん、まあ、それはあなたがその状態を変更できるリソースです。状態を変更するとノイズが発生するため、リソースを少なくしないでください。あなたはバークを動詞(つまり)として見ているので、それをリソースと見なすことはできません。私はその状態を変更できる依存リソースと見なしています。その状態はブール値であるため、エンティティ本体でそれを言及する理由はありません。それは私の意見です。
bolbol 2013年

1

以前のいくつかの回答の改訂では、RPCを使用するよう提案されました。あなたはそれのようにRPCに目を向ける必要がないです RESTの制約に付着しながら、あなたがやりたいことは完全に可能。

まず、URLにアクションパラメータを含めないでください。URLの定義あなたがアクションを適用すると、クエリパラメータはURLの一部です。完全に名詞 と考えるべきです。http://api.animals.com/v1/dogs/1/?action=barkはとは別のリソース(別の名詞)http://api.animals.com/v1/dogs/1/です。[nb Askerが?action=bark質問からURI を削除しました。]たとえば、と比較http://api.animals.com/v1/dogs/?id=1http://api.animals.com/v1/dogs/?id=2ます。クエリ文字列によってのみ区別されるさまざまなリソース。そのため、ボディレスの既存のメソッドタイプ(TRACE、OPTIONS、HEAD、GET、DELETEなど)に直接対応しない限り、リクエストのアクションはリクエストボディで定義する必要があります。

次に、アクションが「べき」であるかどうかを決定します。つまり、悪影響を与えることなく繰り返すことができます(詳細については次の段落を参照)。たとえば、クライアントが目的の効果が発生したかどうか不明な場合は、値をtrueに設定することを繰り返すことができます。彼らは再度リクエストを送信し、値は真のままです。数値に1を加算することはべき等ではありません。クライアントがAdd1コマンドを送信した場合、それが機能したかどうかは不明であり、再度送信した場合、サーバーは1つまたは2つ追加しましたか?あなたがそれを決定したら、のどちらかを選択するためのより良い位置にいるPUTPOST、あなたの方法のために。

べき等とは、結果を変更せずにリクエストを繰り返すことができること意味します。これらの影響には、ロギングやその他のサーバー管理アクティビティは含まれません。最初と2番目の例を使用すると、同じ人に2つのメールを送信すると、1つのメールを送信する場合とは状態が異なります(受信者は受信トレイに2つあり、スパムと見なされる可能性があります)。そのため、私は間違いなくPOSTを使用します。 。例2のbarkCountがAPIのユーザーに表示されることを意図している場合、またはクライアントから見えるものに影響を与える場合、それはまた、要求を非べき等にするものです。自分だけが表示する場合は、サーバーロギングとしてカウントされ、べき等を決定するときに無視する必要があります。

最後に、実行するアクションがすぐに成功することが期待できるかどうかを判断します。BarkDogはすぐに完了するアクションです。RunMarathonはそうではありません。アクションが遅い場合202 Acceptedは、応答本文にURLを含めてを返すことを検討してください。ユーザーがポーリングして、アクションが完了したかどうかを確認できます。または、のようにリストURLにPOSTを/marathons-in-progress/実行し、アクションが完了したら、進行中のID URLからURLにリダイレクトし/marathons-complete/ます。
特定のケース#1および#2の場合、サーバーにキューをホストさせ、クライアントにアドレスのバッチをポストさせます。アクションはSendEmailsではなく、AddToDispatchQueueのようなものです。次に、サーバーはキューをポーリングして、待機中の電子メールアドレスがあるかどうかを確認し、見つかった場合は電子メールを送信します。次に、キューを更新して、保留中のアクションが実行されたことを示します。キューの現在の状態をクライアントに示す別のURIがあります。電子メールの二重送信を回避するために、サーバーはこの電子メールの送信先のログを保持し、各アドレスをチェックして、同じリストに2回POSTした場合でも、同じアドレスに2つ送信しないことを確認できます。待ち行列。

何らかのURIを選択するときは、アクションではなく結果として考えてください。たとえば、「犬」という単語の検索結果google.com/search?q=dogs示します。必ずしも検索を実行するわけではありません。

リストのケース#3および#4も、べき等アクションではありません。提案されているさまざまな効果がAPI設計に影響を与える可能性があることを示唆しています。4つすべてが「世界の状態」を変更するため、4つすべてのケースで同じAPIを使用します。


アクションは、巨大な電子メールキューをチャーンして、多数の人々にメッセージを送信することだとしましょう。それはべき等ですか?PUTまたはPOSTのべき等アクションはありますか?
カークウイメット2013年

@kirk私は私の答えを拡大しました。
ニコラスシャンクス

0

私の新しい答えを見てください -これはこれと矛盾し、RESTとHTTPをより明確かつ正確に説明しています。

たまたまRESTfulですが、唯一の選択肢ではないという推奨事項を次に示します。サービスがリクエストを受け取ったときに吠え始めるには:

POST /v1/dogs/1/bark-schedule HTTP/1.1
...
{"token": 12345, "next": 0, "frequency": 10}

token このリクエストが送信された回数に関係なく、冗長な鳴き声を防ぐ任意の数です。

next次の樹皮の時間を示します。の値0は「できるだけ早く」を意味します。

あなたがいるときはいつでもGET /v1/dogs/1/bark-schedule、あなたはこのようなものを得るはずです、ここでtは最後の樹皮とuの時間ですt + 10分です。

{"last": t, "next": u}

犬の現在の吠え状態を調べるのに使用する吠え声をリクエストするのと同じURLを使用することを強くお勧めします。RESTに必須ではありませんが、スケジュールを変更することを強調しています。

適切なステータスコードはおそらく 205です。現在のスケジュールを確認POSTし、同じURLにアクセスして変更し、変更があったことを証明するためにスケジュールを再確認するようにサービスから指示されるクライアントを想像しています。

説明

残り

ちょっとHTTPを忘れてください。リソースは、入力として時間がかかり、識別子表現を含むセットを返す関数であることを理解することが不可欠です。それを単純化してみましょう。リソースは識別子と表現のセットRです。Rは変更できます-メンバーは追加、削除、または変更できます。(それの悪い、不安定なデザインの識別子を削除または修正するけど。)私たちは、の要素である識別子言うRの識別のR、との要素である表現そのRが表しRを

Rが犬だとしましょう。あなたはたまたまRをとして識別し/v1/dogs/1ます。(意味/v1/dogs/1Rのメンバーです。)これは、Rを識別する多くの方法の1つにすぎません。Rを特定することもできます as /v1/dogs/1/x-raysおよびasとして/v1/rufusます。

Rをどのように表現しますか?たぶん写真で。たぶん、X線のセットが付いています。または、Rが最後に吠えた日付と時刻を示すこともできます。ただし、これらはすべて同じリソースの表現であることを忘れないでください。/v1/dogs/1/x-raysRが最後に吠えたのはいつか」という質問に対する回答で表される同じリソースの識別子です。

HTTP

リソースの複数の表現は、必要な表現を参照できない場合にはあまり役に立ちません。これがHTTPが役立つ理由です。、識別子を表現に接続。つまり、サービスがURLを受け取り、クライアントに提供する表現を決定する方法です。

少なくとも、それGETはそうです。PUT逆数は基本的にGET:あなたはPUT表現rの URLであなたは将来のためにしたい場合GET返すためにそのURLへのリクエストRを HTMLにJSONのようないくつかの可能な翻訳で、。

POST表現を変更するためのより緩い方法です。同じURLに対応する、相互に対応する表示ロジックと変更ロジックがあると考えてください。POSTリクエストは、サービスが適切と考えるように、情報を処理し、表現(同じURLによって配置された表現だけでなく)を変更するための修正ロジックに対する要求です。9.6 PUTの後の3番目の段落に注意してください。URLにあるものを新しいコンテンツに置き換えていません。URLで情報を処理し、有益な表現の形でインテリジェントに応答するように要求しています。

私たちの場合、私たちは修正ロジックを /v1/dogs/1/bark-schedule(最後に吠えたときと次に鳴くときを知らせる表示ロジックの対応物)で情報を処理し、それに応じていくつかの表現を変更するします。今後GETのに対応して、同じURLに対応する表示ロジックは、犬が希望どおりに吠えていることを通知します。

cronジョブは実装の詳細と考えてください。HTTPは、表現の表示と変更を扱います。これ以降、サービスはクライアントが犬が最後に吠えたときと次に吠えるときをクライアントに通知します。サービスの観点から見ると、過去と計画されたcronジョブに対応しているため、正直です。


-1

RESTはリソース指向の標準であり、RPCのようにアクション主導型ではありません。

サーバーを鳴らしたい場合は、JSON-RPCなどのさまざまなアイデアや、WebSocket通信を検討する必要があります。

RESTfulを維持しようとするたびに失敗すると私は考えPOSTていactionます。パラメーターを指定してa を発行しても、新しいリソースは作成されませんが、副作用がある可能性があるため、より安全です。


POST「データのブロックをデータ処理プロセスに提供する」ために設計されました。多くの人がリソースとアクションを区別しているようですが、実際にはアクションは単なるリソースの一種です。サーバー上のアクションリソースを呼び出すことは、キャッシュ可能なモジュール式のスケーラブルな統一インターフェースです。ステートレスでもありますが、クライアントが応答を期待するように設計されている場合は違反する可能性があります。しかし、サーバーで「voidメソッド」を呼び出すことは、Roy FieldingがRESTで意図したものです。
Jacob Stevens 2013年

私の回答で説明しているように RESTでは、サーバーに暗黙的にアクションを実行させることができます。RPCはサーバーに実行を要求するという考えに基づいていますが、これからは「アクションが完了しました」アクション。命令型プログラミングと宣言型プログラミングの両方が理にかなっているように、どちらも完全に理にかなっています。
ジョーダン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.