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

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

REST については基本的な知識しかないことを覚えておいてください。次の URL があるとします。

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

さて、サーバーに犬を吠えさせたいと思います。サーバーだけがこれを行う方法を知っています。CRON ジョブでこれを実行させ、犬を永遠に 10 分ごとに吠えさせたいとします。その呼び出しはどのようになるでしょうか。私は次のようにしたいと思います。

URL リクエスト:

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

リクエスト本文:

{"action":"bark"}

私が独自の HTTP メソッドを作成したことに腹を立てる前に、RESTful な方法でサーバー側メソッドを呼び出す方法について、もっと良いアイデアを教えてください。 :)

明確化のために編集

「bark」メソッドの機能についてもう少し詳しく説明します。異なる構造の API 呼び出しにつながる可能性があるオプションをいくつか示します。

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

ベストアンサー1

RESTful 設計を目指す理由は何ですか?

RESTful原則ウェブサイトを簡単にする機能を提供する(のためにランダムな人間のユーザー「サーフィン」するウェブサービスAPI設計なので、プログラマーにとって使いやすいです。REST は REST であるから良いのではなく、良いから良いのです。そして、それは主に単純

プレーンHTTPのシンプルさ(SOAPエンベロープや単一URIのオーバーロードPOSTサービスなし)は、呼ぶ人もいるかもしれない「機能不足」は、実際にはその最大の強み. HTTPでは、まずアドレス可能性そして無国籍: HTTP を今日のメガサイト (およびメガサービス) にまで拡張可能な状態に保つ 2 つの基本的な設計上の決定。

しかし、REST は万能薬ではありません。時にはRPCスタイル(「リモート プロシージャ コール」 - SOAP など)適切かもしれない時には他のニーズがWebの長所よりも優先されることもあります。これは問題ありません。私たちが本当に気に入らないのは不必要な複雑さプログラマーや企業が、昔ながらの HTTP で問題なく処理できる作業に RPC スタイルのサービスを導入することが多すぎます。その結果、HTTP は、何が「実際に」行われているかを説明する膨大な XML ペイロードのトランスポート プロトコルになってしまいます (URI や HTTP メソッドではそのヒントは得られません)。結果として得られるサービスは複雑すぎてデバッグが不可能で、クライアントが正確なセットアップ開発者の意図どおり。

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

�� 実行できるアクション(「地図上で場所を検索する」)の観点から考えるのではなく...

...という観点から考えてみましょう結果これらのアクション(「検索条件に一致する地図上の場所のリスト」)

以下に例を挙げます。(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"} 文書ではない、それは実際には方法はあなたはしようとしている忍者スニークサービスに参入し、
  • URI/v1/dogs/1/は「犬」リソース (おそらく の付いた犬id==1) を表しており、ドキュメント プロセッサを表していません。

現時点でわかっているのは、上記の設計はそれほど RESTful ではないということだけですが、それは正確には何でしょうか?何が悪いのでしょうか?基本的に、これは複雑な意味を持つ複雑な URI なので良くありません。そこからは何も推測できません。プログラマーは、犬barkに密かに を注入できるアクションがあることをどうやって知るのでしょうかPOST?


質問のAPI呼び出しの設計

それでは、本題に入り、RESTfullにこれらのバークを設計してみましょう。資源の面で引用させてくださいRESTful Web サービス本:

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

上記の説明から、bark次のようにモデル化できるのサブリソースdog(aはbarkdogに含まれているので、つまりbarkは「barked」です。による犬)。

その推論から、私たちはすでに次のことを得ました:

  • その方法はPOST
  • リソースは/barksdog: のサブリソース であり/v1/dogs/1/barksbark「ファクトリー」を表します。その URI は各 dog に対して一意です ( の下にあるため/v1/dogs/{id})。

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

##1. bark は電子メールを送信するだけでdog.email、何も記録しません。

まず、バーキング (電子メールの送信) は同期タスクですか、それとも非同期タスクですか? 次に、barkリクエストにはドキュメント (電子メールなど) が必要ですか、それとも空ですか?


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

このケースは単純です。ファクトリー リソースを呼び出すと、barksすぐに bark (電子メールの送信) が生成され、応答 (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追跡可能です。クライアントはURIGETに を発行してbark、現在の状態を知ることができます。 を使ってDELETEキャンセルすることもできます。


2. barkは電子メールを送信しdog.emaildog.barkCount1ずつ増加します。

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ヘッダーの目的は、クライアントに を確認する必要があることを知らせることですdogHTTP RFCについて303:

このメソッドは主に、POST- スクリプトをアクティブ化ユーザーエージェントを選択したリソースにリダイレクトします。

タスクが非同期の場合、状況barkと同様にサブリソースが必要であり1.2、タスクが完了したとき303に が返される必要があります。GET .../barks/Y


3. bark は、吠えが発生したときの記録を含む新しい " bark" レコードを作成します。また、 1 ずつ増加します。bark.timestampdog.barkCount

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 Acceptedの場合、(HTTP RFCによれば) その代わり。

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


4. bark はシステム コマンドを実行して、最新バージョンの dog コードを Github から取得します。次に、dog.owner新しい dog コードが本番環境にあることを知らせるテキスト メッセージを送信します。

この文言は複雑ですが、実質的には単純な非同期タスクです。

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

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


まとめ

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

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

上記の例では、POSTは均一に設計されています。これにより、犬は「 」になりますbark。これは安全ではありません (吠えることはリソースに影響を及ぼすことを意味します)。また、べき等性もありません (各リクエストは新しい を生成しますbark)。これはPOST動詞によく当てはまります。

プログラマーは、を にするPOSTと がbarks生成されることを知っていますbark。応答ステータス コード (必要に応じてエンティティ本体とヘッダーも含む) は、何が変更されたか、クライアントがどのように処理できるか、またどのように処理すべきかを説明します。

注: 使用された主な情報源は次のとおりです: "RESTful Web サービス「本、HTTP RFCそしてロイ・フィールディングのブログ




編集:

質問とその答えは、最初に作成されて以来、かなり変化してきました。元の質問次のような 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 に保つには、一歩下がって、ここで本当に何をしたいのか (リソースにどのような影響を与えるのか) について考える必要があるかもしれません。

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

さて、注文をキャンセルしたい場合、どうすればいいでしょうか?「キャンセル」 "アクション"として設計します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/canceledtrue

特定のシナリオでは、同様のことを試すことができます。そのようにすると、たとえば犬が吠えているときに、GET/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 動詞 (メソッド) のプロパティ:

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

  • GETHEAD安全(かつべき等性)です。
  • PUTそして、DELETE冪等性のみを持ちます。
  • POSTどちらでもありません。

安全性:GETまたはHEADリクエストは、読むサーバーの状態を変更する要求ではなく、何らかのデータです。クライアントはGETまたはHEAD要求を 10 回行うことができ、それは 1 回行うのと同じです。決して成功しない

冪等性: 一度適用しても複数回適用しても同じ効果が得られる、べき等な操作です (数学では、ゼロを掛けることはべき等です)。DELETEリソースを一度削除した場合、再度削除しても同じ効果が得られます (リソースはGONEすでに削除されています)。

POST安全でもべき等でもありません。POST'factory' リソースに対して 2 つの同一のリクエストを行うと、おそらく同じ情報を含む 2 つの従属リソースが生成されます。 オーバーロードされた (URI またはエンティティ本体のメソッド) ではPOST、すべてが無効になります。

これら 2 つの特性は、HTTP プロトコル (信頼性の低いネットワーク上) の成功にとって重要でした。GETページが完全に読み込まれるまで待たずにページを更新 ( ) した回数はいくつありますか?

作成するアクションこれを URL に配置すると、明らかに HTTP メソッドの規約に違反します。繰り返しますが、テクノロジーではそれが可能であり、実行できますが、それは RESTful な設計ではありません。

おすすめ記事