[解決済み] RESTfulな方法でリソースのサーバーサイドメソッドを呼び出す
質問
私はRESTについて初歩的な理解を持っていることに留意してください。例えば、以下のようなURLがあるとします。
http://api.animals.com/v1/dogs/1/
そして今度は、サーバーが犬を吠えさせるようにしたいのです。この方法はサーバーだけが知っています。例えば、10分ごとに犬を吠えさせるCRONジョブを永遠に実行させたいとします。その呼び出しはどのようなものでしょうか?私はこれをやってみたいのです。
URLをリクエストします。
ACTION http://api.animals.com/v1/dogs/1/
リクエストボディに
{"action":"bark"}
自分でHTTPメソッドを作ったことを怒られる前に、RESTfulな方法でサーバーサイドのメソッドを呼び出す方法について、もっと良いアイデアを教えてください :)
edit for clarification
bark"メソッドが何をするのかについて、もう少し明確にしました。異なる構造のAPIコールをもたらす可能性のあるオプションをいくつか紹介します。
- barkはdog.emailにメールを送信するだけで、何も記録しません。
- barkはdog.emailにメールを送り、dog.barkCountを1だけ増加させます。
- barkは、吠えが発生した日時を記録したbark.timestampを使用して、新しい"bark"レコードを作成します。また、dog.barkCountを1だけ増加させます。
- bark はシステムコマンドを実行し、Github から最新バージョンの dog コードを取得します。そして dog.owner にテキストメッセージを送り、新しい dog コードが実稼働していることを伝えます。
解決するには?
なぜRESTfulな設計を目指すのか?
RESTfulの原則 Webサイトを簡単にする機能をもたらす は ランダムな人間のユーザー を使用する) ウェブサービスAPIの設計に そのため、プログラマーにとって使いやすいものとなっています。 RESTはRESTだから良いのではなく、良いから良いのです。 そして、それが良いのは、ほとんどが シンプル .
プレーンなHTTPのシンプルさ(SOAPエンベロープやシングルURIのオーバーロードがない)。
POST
サービス)、何
と呼ぶ人もいます。
機能不足。
は、実際には
<強い
最大の強み
. HTTPでは、まず最初に
アドレス指定可能
と
ステートレス
この2つの基本的な設計上の決定により、今日のメガサイト(およびメガサービス)に対応するHTTPのスケーラビリティが維持されています。
しかし、RESTは銀の雄たけびを上げるものではありません。 時にはRPCスタイルの ("Remote Procedure Call" - SOAPなど)。 適切な場合があります。 そして、時にはWebの良さよりも他のニーズが優先されることもあります。これはいいことです。私たちがあまり好きではないのは は、不必要な複雑さ . プログラマや企業が、古いHTTPで十分に処理できる仕事にRPCスタイルのサービスを持ち込むことがあまりに多いのです。その結果、HTTPは、何が起こっているのかを説明する巨大なXMLペイロードのためのトランスポートプロトコルに成り下がってしまいます(URIやHTTPメソッドは、それについての手がかりを与えてくれません)。その結果、サービスはあまりに複雑で、デバッグが不可能になり、クライアントが 正確な設定 開発者が意図したとおりに
同じようにJava/C#のコードも ない HTTPを使うだけでは、RESTfulなデザインとは言えません。という焦りにとらわれるかもしれません。 考える サービスについて アクションとリモートメソッドの観点から を呼び出す必要があります。これでは、ほとんどがRPC-Styleのサービス(またはREST-RPC-hybrid)になってしまうのも無理はありません。最初のステップは、違う考え方をすることです。RESTfulな設計は多くの方法で実現できます。 アプリケーションをアクションではなく、リソースの観点から考える。
<ブロッククオート???? 地図上の場所を検索する」というようなアクションを考えるのではなく
...の観点から考えるようにします。 結果 これらのアクション("検索条件に一致する地図上の場所のリスト")について。
以下、例を挙げて行きます。 (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/
は、quot;document processor"(工場的)なURIでした。 <サブ document processor"とは、ただ物を投げて("srowing")そのことを忘れてしまうようなURIのことです。例えば、メッセージブローカーサービスにメッセージを投稿するためのURIで、投稿後にメッセージの処理状況を示すURIにリダイレクトされるようなものです。
あなたのシステムについて詳しくは知らないが、両方とも真実でないことは間違いないだろう。
-
{"action":"bark"}
はドキュメントではありません というのは、実際には は、メソッド にしようとしている。 ニンジャスニーク サービスへ参入する。 -
その
/v1/dogs/1/
URIは、"dog"リソースを表します(おそらく、犬はid==1
) であり、ドキュメントプロセッサではありません。
さて、今わかっていることは、上のデザインはあまりRESTfulではないということですが、具体的にはどうなのでしょうか?
何がそんなに悪いのか?
基本的には、複雑な意味を持つ複雑なURIであることが悪いのです。そこから何かを推論することはできません。プログラマはどうやって犬が
bark
というアクションを密かに注入することができます。
POST
を入れるのですか?
質問のAPIコールを設計する
では、本題に入り、これらのバークをREST的にデザインしてみることにしよう。 リソースの観点から . を引用させてください。 レストフルウェブサービス の本に書かれています。
A
POST
リクエストは、既存のリソースから新しいリソースを作成する試みです。 があります。既存のリソースは、新しいリソースの親になる可能性があります。 データ構造の意味で、ツリーのルートがすべての そのリーフノードの あるいは、既存のリソースが特別な "ファクトリー"。 リソースは、他のリソースを生成することだけが目的である。そのため と共に送信される表現POST
リクエストは初期状態を記述します。 の状態を表示します。PUTと同様にPOST
リクエストは必要ありません。 は表現を全く含まない。
上記の記述に従うと、次のようになります。
bark
は次のようにモデル化することができます。
のサブリソースです。
dog
(ある
bark
は犬の中に含まれる、つまり、吠えるは "barked"。
によって
a dog)である。
その推論から、私たちはすでに
-
このメソッドは
POST
-
リソースは
/barks
dog のサブリソースです。/v1/dogs/1/barks
を表します。bark
ファクトリー"です。このURIはそれぞれの犬に対して一意であり、(それは/v1/dogs/{id}
).
これで、リストの各ケースが特定の動作をするようになりました。
##1. バークはメールを送信するだけです。
dog.email
で、何も記録しない。
まず、吠える(メールを送る)ことは同期タスクなのか非同期タスクなのか?次に
bark
リクエストは何かドキュメント(メールとか)を必要としますか、それとも空ですか?
1.1 バークがメールを送る先
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
をクリックするとキャンセルされます。
2.バークは、次のようなメールを送信します。
dog.email
をインクリメントし、さらに
dog.barkCount
1ずつ
これはもっと厄介なことで、もしクライアントが
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
を追加しました。更新された犬は、その中に "documented"することができます。
GET dogs/X/barks/Y
と同じです。
4. バークはシステムコマンドを実行し、Githubから最新版のdogコードを引き降ろす。その後、テキストメッセージを
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
の動詞がよく出てきます。
プログラマーなら知っているはず:a
POST
から
barks
は
bark
. レスポンスステータスコード(必要に応じてエンティティボディとヘッダも)は、何が変更され、クライアントがどのように処理できるのか、また処理すべきなのかを説明する役割を果たします。
<サブ 注:使用した主なソースは以下の通り: " レストフルウェブサービス という本があります。 HTTP RFC と ロイ・フィールディングのブログ .
編集する
質問とその回答は、最初に作成されたときとはかなり変わっています。その 元の質問 のようなURIの設計について質問しています。
ACTION http://api.animals.com/v1/dogs/1/?action=bark
以下、その理由を説明します。
クライアントがサーバーに伝える方法 何をするか は、データに対して メソッド情報 .
- RESTfulなウェブサービスは、HTTPメソッドでメソッド情報を伝える。
- 一般的なRPC-StyleやSOAPサービスでは、エンティティボディとHTTPヘッダにその内容を保持します。
どの部分 クライアントがサーバーに操作させたい]データの スコープ情報 .
- RESTfulなサービスではURIを使用します。SOAP/RPC-Style サービスでは、再び entity-body と HTTP ヘッダーを使用します。
例として、GoogleのURIを挙げてみよう。
http://www.google.com/search?q=DOG
. そこでは、メソッド情報は
GET
で、スコープ情報は
/search?q=DOG
.
長い話ですが
- で RESTfulアーキテクチャ の場合、メソッド情報はHTTPメソッドに入ります。
- で リソース指向アーキテクチャー で、スコープ情報はURIに入る。
そして経験則。
HTTPメソッドとメソッド情報が一致しない場合、そのサービスはRESTfulではありません。スコープ情報がURIにない場合、そのサービスはリソース指向ではありません。
をつけることができます。
"bark"。
"アクション"
をURL内(またはエンティティボディ内)に記述し
POST
. これは問題なく動作しますし、最もシンプルな方法かもしれません。
しかし、これはRESTfulではありません
.
あなたのサービスを本当にRESTfulに保つためには、一歩下がって、ここで本当にやりたいこと(リソースにどんな影響を与えるか)を考える必要があるかもしれません。
あなたの具体的なビジネスニーズについて話すことはできませんが、例を挙げましょう。RESTful な注文サービスでは、注文は次のような URI で行われます。
example.com/order/123
.
さて、注文をキャンセルしたい場合、どのようにすればよいのでしょうか?と考えたくなるかもしれませんが、それは
キャンセル
"アクション"
というようにデザインします。
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
というエンティティボディを持つ
true
は、簡略化のため、利用可能であってもよい)。
あなたの具体的なシナリオでは、似たようなことを試してみるとよいでしょう。そうすれば、例えば犬が吠えている間に
GET
で
/v1/dogs/1/
は、その情報を含めることができます
(例)
<barking>true</barking>
)
. あるいは......それがあまりに複雑な場合は、RESTfulな要件を緩めて
POST
.
アップデートする
あまり答えを大きくしたくないのですが、アルゴリズムを公開するコツをつかむのに時間がかかるので、(1)(2)(3)(4)(5)(6)のようにしました。 アクション をリソースのセットとして使用します。アクションの観点で考えるのではなく、( 地図上の場所を検索してください。 )、その行動の結果という観点で考える必要がある( 検索条件に一致する地図上の場所のリスト。 を選択します。 ).
もし、あなたのデザインがHTTPの統一されたインターフェイスに合わないことがわかったら、このステップに戻ってくることになるかもしれません。
クエリ変数
は
スコープ情報
を使用しますが
ではなく
新しいリソースを表す (
/post?lang=en
は明らかに
同じ
リソースとして
/post?lang=jp
表現が違うだけです)。むしろ、これらは
クライアントの状態
(例えば
?page=10
というように、その状態はサーバーに保持されない。
?lang=en
もその一例です)または
入力パラメータ
から
アルゴリズミック・リソース
(
/search?q=dogs
,
/dogs?code=1
). ここでも、個別のリソースではありません。
HTTP動詞の(メソッドの)プロパティ。
を示すもう一つの明確なポイント
?action=something
がRESTfulでないのは、HTTP動詞の特性によるものです。
-
GET
とHEAD
は安全(かつべき乗)である。 -
PUT
とDELETE
はべき乗のみである。 -
POST
はどちらでもない。
安全性
: A
GET
または
HEAD
のリクエストは
読む
あるデータ、サーバーの状態を変更するリクエストではありません。クライアントは
GET
または
HEAD
を10回リクエストすれば、1回作るのと同じになる、あるいは
全く作らない
.
べき乗
: べき乗の演算とは、一度だけ適用しても二度以上適用しても同じ効果を持つ演算のことです(数学ではゼロの掛け算がべき乗になります)。もし、あなたが
DELETE
を一度削除すれば、再度削除しても同じ効果が得られます(リソースは
GONE
を使用します)。
<サブ
POST
は安全でもなければべき乗でもない。つの同じ
POST
ファクトリー'リソースへのリクエストは、おそらく、同じ
情報を提供します。オーバーロードされた(URIまたはentity-bodyのメソッド)場合
POST
は、すべての賭けに出る。
この2つの特性は、HTTPプロトコルの成功にとって(信頼性の低いネットワーク上で!)重要なものでした:あなたは何回(
GET
)が完全に読み込まれるまで待たずに、ページを表示することができますか?
を作成する アクション をURL内に配置することは、明らかにHTTPメソッドの契約を破ることになります。もう一度言いますが、技術的には可能ですが、それはRESTfulな設計ではありません。
関連
-
[解決済み] cURLでJSONデータをPOSTするにはどうすればよいですか?
-
[解決済み] RESTを理解する。動詞、エラーコード、認証
-
[解決済み] cURLを使ってCookieを送信するには?
-
[解決済み】REST APIでのPUTメソッドとPATCHメソッドの使い分け 実生活でのシナリオ
-
[解決済み】Spring経由のRESTful認証
-
[解決済み】REST API - ファイル(画像)処理 - ベストプラクティス
-
[解決済み】REST認証スキームの安全性
-
[解決済み] REST API 認証
-
[解決済み] オブジェクト内のアイテムの合計数を返すための最良のRESTfulメソッドは何ですか?
-
[解決済み] RESTを使った複数レコードの削除
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] リソースが既に存在する場合の POST に対する HTTP レスポンスコード
-
[解決済み] API のバージョン管理に関するベストプラクティス?[クローズド]
-
[解決済み] cURLでPUTリクエストを行うには?
-
[解決済み] cURLを使ってCookieを送信するには?
-
[解決済み] REST API 認証
-
[解決済み] RESTのPUT/POST/DELETEコールは、規約によって何を返すべきですか?
-
[解決済み] RESTでトランザクション?
-
[解決済み] RESTとは?若干の混乱【終了
-
[解決済み] RESTを使った複数レコードの削除
-
[解決済み] REST - ボディにIDを入れるかどうか?