web-dev-qa-db-ja.com

REST APIはコマンド/アクションベースのドメインにどのように適合しますか?

この中で 記事 著者はそれを主張している

場合によっては、本質的にRESTfulでない操作をAPIで公開する必要があります。

そしてそれ

APIのアクションが多すぎる場合は、RESTfulの原則を使用するのではなく、RPCの視点で設計されているか、問題のAPIがRPCタイプモデルに適していることを示しています。

これは、私が他で読んだり聞いたりしたことも反映しています。

しかし、これは非常に混乱しているので、この問題をよりよく理解したいと思います。

例I:VM through a REST interface

VMのシャットダウンをモデル化するには、根本的に異なる2つの方法があると思います。それぞれの方法にはいくつかのバリエーションがあるかもしれませんが、今のところ最も基本的な違いに集中しましょう。

1.リソースの状態プロパティにパッチを適用します

PATCH /api/virtualmachines/42
Content-Type:application/json  

{ "state": "shutting down" }

(または、サブリソースのPUT/api/virtualmachines/42/state。)

VMはバックグラウンドでシャットダウンします。シャットダウンは成功するか、電源オフで状態が内部的に更新されないかによって、しばらくしてからシャットダウンされます。

2. PUTまたはPOSTリソースのアクションプロパティ

PUT /api/virtualmachines/42/actions
Content-Type:application/json  

{ "type": "shutdown" }

結果は最初の例とまったく同じです。状態はすぐに「シャットダウン」に更新され、最終的には「電源オフ」に更新されます。

どちらのデザインもRESTfulですか?

どのデザインが良いですか?

例II:CQRS

複数の集約の更新につながる可能性がある、または具象リソースとサブリソースのCRUD操作にマップできない可能性のある「アクション」(別名コマンド)が多数あるCQRSドメインがある場合はどうなりますか?

可能な限り、具象リソースに対する具象作成または更新と同じくらい多くのコマンドをモデル化して(例Iの最初のアプローチに従って)、残りに「アクションエンドポイント」を使用する必要がありますか?

または、すべてのコマンドをアクションエンドポイントにマッピングする必要がありますか(例Iの2番目のアプローチのように)?

どこに線を引くべきですか?設計がRESTfulでなくなるのはいつですか?

CQRSモデルはRPCのようなAPIに適していますか?

上記の引用テキストによると、私が理解しているとおりです。

私の多くの質問からわかるように、私はこのトピックについて少し混乱しています。それをよりよく理解するのを手伝ってくれませんか?

25
leifbattermann

最初のケース(VMのシャットダウン)では、RESTfulなOPの代替案はありません。確かに、 Richardson成熟度モデル を尺度として使用する場合、リソースと動詞を使用するため、両方がレベ2APIです。

ただし、どちらもハイパーメディアコントロールを使用しておらず、私の意見では、これはRPCからの唯一のタイプREST that differentiates RESTful API design from RPC。つまり、stickレベル1および2では、ほとんどの場合、RPCスタイルのAPIを使用します。

VMをシャットダウンする2つの異なる方法をモデル化するために、VM自体を(とりわけ)リンクを含むリソースとして公開します。

{
    "links": [{
        "rel": "shut-down",
        "href": "/vms/1234/fdaIX"
    }, {
        "rel": "power-off",
        "href": "/vms/1234/CHTY91"
    }],
    "name": "Ploeh",
    "started": "2016-08-21T12:34:23Z"
}

クライアントがPloeh VMをシャットダウンする場合は、shut-down関係タイプを使用してリンクを追跡する必要があります。 (通常、 RESTful Web Services Cookbook で概説されているように、関係タイプにはIRIまたはより複雑な識別スキームを使用しますが、この例はできるだけ単純にすることにしました。)

この場合、アクションで提供する他の情報はほとんどないため、クライアントはhrefのURLに対して空のPOSTを作成するだけです。

POST /vms/1234/fdaIX HTTP/1.1

(このリクエストには本体がないため、これをGETリクエストとしてモデル化するのは魅力的ですが、GETリクエストには目に見える副作用がないはずなので、POSTの方が正しいです。)

同様に、クライアントがVMの電源をオフにしたい場合は、代わりにpower-offリンクをたどります。

言い換えれば、リンクの関係タイプは、意図を示すaffordancesを提供します。それぞれの関係タイプには、特定の意味上の意味があります。これがセマンティックウェブについて時々話す理由です。

例をできるだけ明確にするために、各リンクのURLを意図的に覆い隠しました。ホスティングサーバーが受信リクエストを受信すると、fdaIXシャットダウンを意味し、CHTY91電源オフを意味することがわかります。

通常、私はURL自体にアクションをエンコードするだけなので、URLは/vms/1234/shut-down/vms/1234/power-offになりますが、教えるときは、関係タイプ(セマンティクス)とURL(実装)の区別が曖昧になります詳細)。

使用しているクライアントに応じて、 RESTful URLをハッキング不可能にする を検討できます。

CQRS

CQRSに関しては、Greg YoungとUdi Dahanが同意する数少ないことの1つはCQRSがトップレベルのアーキテクチャではないということです。したがって、RESTful APIをCQRSのようにすることには注意が必要です。これは、クライアントがアーキテクチャの一部になることを意味します。

多くの場合、実際の(レベル3)RESTful APIの原動力は、クライアントを壊すことなく、またクライアントを制御することなく、APIを進化させたいことです。それがあなたの動機であれば、CQRSは私の最初の選択肢にはなりません。

20
Mark Seemann

VM = a RESTインターフェースを介して

これは実際にはいくぶん有名な例で、 Tim Bray、2009年 によって発表されました。

ロイフィールディング、問題について話し合う この観察を共有した

個人的には、監視された状態(電源状態など)を編集不可として扱うシステムを好みます。

つまり、監視対象の状態の現在の表現を返す情報リソースが1つあります。その表現には、その状態への変更を要求するform thatへのハイパーメディアリンクが含まれる場合があり、フォームには、(各)変更要求を処理するためのリソースへの別のリンクがあります。

Seth Ladd は、問題について重要な洞察を得ました

Runningを人の単純な状態から、作成、更新、および話題にできる真の名詞に変えました。

これをマシンの再起動に戻します。私はあなたがPOST to/vdc/434/cluster/4894/server/4343/rebootsするだろうと主張します投稿したら、あなたはthisを表すURIを持っています=再起動すると、GETしてステータスを更新できます。ハイパーリンクの魔法によって、再起動の表現は再起動されたサーバーにリンクされます。

URIスペースの作成は安価であり、URIはさらに安価だと思います。名詞としてモデル化されたアクティビティのコレクションを作成し、POST、PUT、DELETEを実行します。

RESTfulプログラミングは、WebスケールのVogon官僚機構です。 anything RESTfulをどのように実行しますか?そのための新しい書類を発明し、書類をデジタル化します。

やや洗練された言語では、「仮想マシンをシャットダウンする」ためにドメインアプリケーションプロトコルを定義し、そのプロトコルを公開/実装するために必要なリソースを特定しています。

自分の例を見る

PATCH /api/virtualmachines/42
Content-Type:application/json  

{ "state": "shutting down" }

それで大丈夫です;リクエスト自体を独自の個別の情報リソースとして実際に処理しているわけではありませんが、それでも管理できます。

変化の表現を少し見逃しました。

ただし、PATCHでは、囲まれたエンティティに、現在Originサーバーにあるリソースを変更して新しいバージョンを作成する方法を説明する一連の指示が含まれています。

たとえば、 JSON Patch メディアタイプは、JSONドキュメントを直接変更しているかのように命令をフォーマットします

[
    { "op": "replace", "path": "state", "value": "shutting down" }
]

あなたの代わりに、アイデアは近いですが、明らかに正しいわけではありません。 PUTはリソースの状態を完全に置き換えたものですターゲットURLでなので、collectionのようなスペルを選択することはおそらくないでしょう。 singleエンティティの表現のターゲット。

POST /api/virtualmachines/42/actions

キューにアクションを追加しているというフィクションと一致しています

PUT /api/virtualmachines/42/latestAction

キューの最後の項目を更新しているというフィクションと一致しています。この方法で行うのは少し変です。最小の驚きの原則は、すべてのPUTを1つの場所に配置して複数のリソースを同時に変更するのではなく、各PUTに固有の識別子を与えることをお勧めします。

URIのスペルについて説明している限り、-RESTは関係ありません; /cc719e3a-c772-48ee-b0e6-09b4e7abbf8bは、RESTに関する限り、完全なURIです。読みやすさは、変数名と同様に、別の問題です。 RFC 3986 と一致するスペルの使用peopleがもっと楽しくなります。

CQRS

複数の集約の更新につながる可能性がある、または具象リソースとサブリソースのCRUD操作にマップできない可能性のある「アクション」(別名コマンド)が多数あるCQRSドメインがある場合はどうなりますか?

CQRSのグレッグヤング

CQRSは非常に単純なパターンであり、他の方法では存在しない可能性があるアーキテクチャの多くの機会を可能にします。 CQRSは結果整合性ではなく、イベント発生ではなく、メッセージングではなく、読み取りと書き込みのモデルが分離されておらず、イベントソーシングを使用していません。

ほとんどの人がCQRSについて話すとき、彼らは本当にアプリケーションのサービス境界を表すオブジェクトにCQRSパターンを適用することについて話しています。

HTTP/RESTのコンテキストでCQRSについて話していることを考えると、この後者のコンテキストで作業していると想定するのは理にかなっているようです。

これは驚くべきことに、前の例よりもさらに簡単です。これの理由は単純です:コマンドはメッセージです

Jim Webber は、1950年代のオフィスのアプリケーションプロトコルとしてHTTPについて説明しています。仕事は、メッセージを受け取り、受信トレイに入れることによって行われます。同じ考えが成り立ちます-私たちはフォームの空のコピーを取得し、私たちが知っている詳細を記入して、それを配送します。多田

可能な限り、具象リソースに対する具象作成または更新と同じくらい多くのコマンドをモデル化して(例Iの最初のアプローチに従って)、残りに「アクションエンドポイント」を使用する必要がありますか?

はい、「具体的なリソース」がドメインモデルのエンティティではなくメッセージである限り。

重要なアイデア:REST APIはインターフェイスのままです。クライアントがメッセージを変更する必要なく、基になるモデルを変更できるはずです。新しいモデルをリリースするとき、ドメインプロトコルを取得して新しいモデルに適用する方法を知っているWebエンドポイントの新しいバージョンをリリースします。

CQRSモデルはRPCのようなAPIに適していますか?

特にありません。特に、Webキャッシュは「結果的に一貫した読み取りモデル」の良い例です。各ビューを個別にアドレス指定可能にし、それぞれに独自のキャッシュルールを設定すると、無料で大量のスケーリングを利用できます。読み取りに対するRPCのみのアプローチには、あまり魅力がありません。

書き込みの場合、これはよりトリッキーな質問です。単一のエンドポイントまたは単一のエンドポイントファミリーの単一のハンドラーにすべてのコマンドを送信することは、確かに簡単です。 RESTは、エンドポイントがクライアントに通信する場所を見つける方法についての詳細です。

メッセージを独自の固有のリソースとして扱うことには、PUTを使用できるという利点があります。中間コンポーネントにメッセージの処理がべき等であることを警告し、エラー処理の特定のケースに参加できるので便利です。 。 (注:クライアントの観点から見ると、リソースのURIが異なる場合、それらは異なるリソースです。Originサーバー上ですべて同じリクエストハンドラーコードを持つ可能性があるという事実は、ユニフォームによって隠された実装の詳細ですインターフェース)。

フィールディング(2008)

上記はまだ完全にRESTfulではないことにも注意してください。少なくとも私がこの用語をどのように使用しているか。私がやったことはすべて、RPCに過ぎないサービスインターフェースについての説明です。 RESTfulにするためには、サービスを導入して定義するハイパーテキストを追加し、フォームやリンクテンプレートを使用してマッピングを実行する方法を説明し、視覚化を便利な方法で組み合わせるコードを提供する必要があります。

6
VoiceOfUnreason

5レベルのメディアタイプ を利用して、リクエストのcontent-typeヘッダーフィールドにコマンドを指定できます。

VMの例では、これらの線に沿ったものになります

PUT /api/virtualmachines/42
Content-Type:application/json;domain-model=PowerOnVm

> HTTP/1.1 201 Created
Location: /api/virtualmachines/42/instance

その後

DELETE /api/virtualmachines/42/instance
Content-Type:application/json;domain-model=ShutDownVm

または

DELETE /api/virtualmachines/42/instance
Content-Type:application/json;domain-model=PowerOffVm

https://www.infoq.com/articles/rest-api-on-cqrs を参照してください

2
guillaume31

リンクされた記事の例は、モデル化されたリソースの状態の変化ではなく、コマンドによってマシンを起動およびシャットダウンする必要があるという考えに基づいています。後者は、RESTが生きて呼吸するものとほぼ同じです。 VMのより良いモデリングには、実際の対応物がどのように機能するか、そして人間としてのそれとどのように相互作用するかを検討する必要があります。これは長い間ですが、良いモデリングを行うために必要な思考のタイプについての良い洞察を与えると思います。

机の上のコンピュータの電源状態を制御する方法は2つあります。

  • 電源スイッチ:電源への電力の流れを即座に遮断し、コンピューター全体を突然、無秩序に停止させます。
  • オン/オフボタン:外部の何かがすべてのシャットダウンを要求していることをソフトウェアに通知するようにハードウェアに指示します。ソフトウェアは正常にシャットダウンし、ハードウェアに通知してシャットダウンし、ハードウェアはスタンバイ状態に移行できることを電源装置に通知します。電源スイッチがオンで、マシンが実行中で、ソフトウェアがシャットダウン信号に応答できない状態の場合、電源スイッチをオフにしない限り、システムはシャットダウンしません。 (VMはまったく同じように動作します。シャットダウン信号がソフトウェアによって無視された場合、マシンは実行を継続します。強制的に電源を切る必要があります。)再起動できるようにしたい場合マシンの電源スイッチを入れ直してから、オン/オフボタンを押す必要があります。 (多くのコンピューターには、電源ボタンを長押しして直接スタンバイ状態にするオプションがありますが、このモデルでは実際には必要ありません。)このボタンを押すと動作が異なるため、トグルスイッチのように扱うことができます。押したときの状態に応じて。電源スイッチがオフの場合、このボタンを押しても何も起こりません。

VMの場合、これらの両方をブール値の読み取り/書き込みとしてモデル化できます。

  • power-trueに変更すると、スイッチがこの状態になったことを通知する以外は何も起こりません。 falseに変更すると、VMは即時電源オフ状態になるように命令されます。完全を期すために、書き込み後に値が変更されていない場合、何も起こりません。

  • onoff-trueに変更した場合、powerfalseの場合は何も起こりません。それ以外の場合は、VMを開始するように命令します。 falseに変更した場合、powerfalseの場合は何も起こりません。それ以外の場合は、VMは、ソフトウェアに通常のシャットダウンを実行するように通知するように命令されます。電源オフ状態になる可能性があります。繰り返しになりますが、完全を期すために、変更なしの書き込みは何もしません。

これにより、マシンの状態がスイッチの状態を反映していない状況が1つあり、それがシャットダウン中に発生することがわかります。 powerは引き続きtrueで、onofffalseのままですが、プロセッサはシャットダウンを実行しているため、別のリソースを追加して、マシンが実際に何を行っているかを確認する必要があります。

  • running-VMが実行されている場合はtrueであり、実行されていない場合はfalseである読み取り専用の値。ハイパーバイザの状態を確認することで決定されます。

この結果、VMを起動する場合は、powerおよびonoffリソースがtrueに設定されていることを確認する必要があります。 (powerステップを自動リセットすることでスキップできるようにすることができます。そのため、falseに設定すると、VMが検証可能にハードストップされた後、trueになります。それがRESTfulに純粋なものかどうか正常にシャットダウンする場合は、onofffalseに設定し、後で戻ってマシンが実際に停止したかどうかを確認します。そうでない場合は、powerfalseに設定します。

現実の世界と同様に、VMをonofffalseに変更した後、VMを開始するように指示されるという問題がありますが、シャットダウンの途中であるため、依然としてrunningです。あなたがそれにどう対処するかは政策決定です。

1
Blrfl

どちらのデザインもRESTfulですか?

したがって、安静に考えたい場合は、コマンドを忘れてください。クライアントはサーバーにVMをシャットダウンするように指示しません。クライアントは、状態を更新してリソース表現のコピーを「隠し」(比喩的に言えば)、サーバーにその表現をPUTします。サーバーはその新しい状態表現を受け入れ、これの副作用として、実際にはVMをシャットダウンします。副作用の側面はサーバーに任されています。

少ない

ちょっとサーバー、ここにクライアント、VMをシャットダウンしてよろしいですか

などの

ちょっとサーバー、ここにクライアント、私はリソースの状態を更新しましたVM 42をシャットダウン状態にして、このリソースのコピーを更新してから、適切だと思うことをすべて実行してください

この新しい状態を受け入れるサーバーの副作用として、サーバーは実際に実行する必要があるアクション(物理的にシャットダウンするVM 42)など)を確認できますが、これはクライアントに対して透過的です。クライアントこの新しい状態と一致するためにサーバーが実行する必要があるアクションには関係ありません

コマンドを忘れてください。唯一のコマンドは、状態転送のためのHTTPの動詞です。クライアントは、サーバーが物理的なVM=をシャットダウンの状態にする方法)を知りませんし、気にしません。クライアントは、サーバーにコマンドを発行せず、これはただ言っているだけですこれは新しい状態です、理解してください

これの威力は、フロー制御の観点から、クライアントをサーバーから切り離すことです。後でサーバーがVMでの動作を変更しても、クライアントは気にしません。更新するコマンドエンドポイントはありません。 RPCでは、APIエンドポイントをshutdownからshut-downに変更すると、サーバーで呼び出すコマンドがわからなくなるため、すべてのクライアントが壊れます。

RESTは宣言型プログラミングに似ており、何かを変更するための一連の指示をリストする代わりに、希望する方法を記述して、プログラミング環境にそれを認識させます。

0
Cormac Mulhall