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
が追跡可能です。次に、クライアントGET
はbark
URIにを発行して、現在の状態を知ることができます。多分それ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.2
303
GET .../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 Accepted
(HTTP 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
次に、クライアントはGET
sを発行し/v1/dogs/1/barks/a65h44
て現在の状態を確認します(コードがプルされた場合は、所有者などに電子メールが送信されます)。犬が変わるたびに、a 303
が適用されます。
まとめ
ロイ・フィールディングの引用:
RESTがメソッドに必要とする唯一のことは、すべてのリソースに対してそれらが均一に定義されることです(つまり、仲介者がリクエストの意味を理解するためにリソースタイプを知る必要がないようにします)。
上記の例でPOST
は、は均一に設計されています。犬「bark
」になります。これは安全ではありません(つまり、樹皮がリソースに影響を与えることを意味しますbark
)POST
。
プログラマが知っているだろう:A POST
のbarks
収穫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
を使用して、の新しい表現を作成できます。order
canceled
true
PUT /order/123 HTTP/1.1
Content-Type: application/xml
<order id="123">
<customer id="89987">...</customer>
<canceled>true</canceled>
...
</order>
以上です。注文をキャンセルできない場合は、特定のステータスコードを返すことができます。(POST /order/123/canceled
entity-bodyのようなサブリソース設計true
も、簡単にするために利用できる場合があります。)
特定のシナリオでは、同様のことを試すことができます。そのようにして、例えば犬が吠えている間、GET
at /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=something
URIでRESTfulでないことを示すもう1つの明確な点は、HTTP動詞のプロパティです。
GET
そしてHEAD
安全です(そしてべき等です);
PUT
そしてDELETE
唯一の冪等です。
POST
どちらでもありません。
安全性:GET
or HEAD
要求は、データを読み取るための要求であり、サーバーの状態を変更するための要求ではありません。クライアントはGET
またはをHEAD
10回作成でき、1回作成するのと同じか、まったく作成しないのと同じです。
べき等:1回でも2回以上適用しても同じ効果を持つ1 つのべき等演算(数学では、ゼロを掛けることはべき等です)。DELETE
リソースを1度使用した場合、再度削除しても同じ効果があります(リソースはGONE
既に存在しています)。
POST
安全でもべき等でもありません。POST
「ファクトリ」リソースに対して2つの同一のリクエストを行うと、おそらく2つの下位リソースに同じ情報が含まれます。オーバーロード(URIまたはエンティティ本体のメソッド)を使用するとPOST
、すべてのベットが無効になります。
これらのプロパティは両方とも、HTTPプロトコルの成功(信頼性のないネットワーク上で!)にとって重要でした。GET
ページが完全に読み込まれるまで待たずに、ページを何回更新()しましたか?
アクションを作成してURLに配置すると、HTTPメソッドのコントラクトが明らかに破られます。繰り返しますが、このテクノロジーにより可能になりますが、それは可能ですが、それはRESTfulな設計ではありません。