POSTの前にプレビューを表示するRESTエンドポイント


17

RESTバックエンドとHTML + JSフロントエンドを搭載した新しいWebアプリケーションを設計しています。

1つのエンティティを変更するためのPOSTメソッドが1つあり(Configを呼び出しましょう)、アプリケーションの多くの要素の状態にいくつかの副作用があります。POSTが次のように実行されると仮定します。

POST /api/config BODY {config: ....}

このため、これらの変更が行われる前にプレビューを表示して、エンドユーザーが何が変更されるかを確認できるようにします。

私が最初に考えたのは、プレビューのGETエンドポイントを作成して、エンティティの新しい状態の本体を送信することです。こちらです:

GET /api/preview/items BODY {config: ....}

新しい構成のアイテムの新しい状態が表示される場合があります。

GET /api/preview/sales BODY {config: ....}

新しい構成での販売の新しい状態が表示される場合があります。

アプリケーションの状態を変更しないので、GET動詞を使用することをお勧めします。ただし、GET要求での要求本体の使用は推奨されないようです。

これについて良い習慣はありますか?他の選択肢として、1つの方法で構成をドラフトとして保存し、他の方法で結果を表示することもできますが、追加の手順が必要で、サーバーでドラフトを管理する必要があります。

POST /api/preview/config BODY {config: ....}

GET /api/preview/items?idPreviewConfig=1

この設定は正確に何であり、どのようにitemsor に影響しsalesますか?返されるエンティティの表現に影響しますか?
アンディ

アイテムと販売の両方が、設定で行った変更の影響を受けるとしましょう。
エクストリームバイカーはモニカを復活させる

しかし、変更はどういう意味ですか?返されるエンティティのセットを変更しますか?返される構造は変わりますか?
アンディ

実際には、POSTする構成に応じて、itemsおよびsales(構造ではなく)の値を変更します。
エクストリームバイカー、モニカを

そして、構成は正確にどのくらいですか?数百キロバイトまで成長できますか?
アンディ

回答:


27

これはドメイン固有であるため、HTTPでネイティブサポートできません。

代わりに、次のいずれかを実行できます。

  1. がありPOST /api/config/previewます。サーバー側では、アプリケーションは実際の構成を変更してはならないことを認識しますが、実際の構成と投稿した構成を組み合わせ、変更内容を示す結果を返します。

    その後、ユーザーが結果に満足したらPOST /api/config、前のリクエストと同じペイロードを含むを実行します。これにより、構成が効果的に上書きされます。

    このアプローチの利点は、現在のAPIに重大な変更を加えないことです。プレビュー機能を必要としないクライアントは、以前と同じようにエントリを更新できます。

    欠点は、本体が大きい場合、サーバーに2回送信する必要があることを意味します。この場合、次のアプローチを使用できます。

  2. 持っているPOST /api/config/prepare(例えば、一時的なレコードのID:一時的なレコードで送信されたものを記憶し、二つのことを返す12345)と変更のプレビューを。

    ユーザーが結果に満足している場合、ユーザーはPOST /api/config/commit/12345変更を確実に保存するためにを実行します。そうでない場合、一時レコードはしばらく保持され、cronジョブによって破棄される場合があります。

    利点は、ここでも、元のPOST /api/configファイルをそのまま保持でき、プレビューを必要としないクライアントが壊れないことです。

    欠点は、(1)一時レコードの削除を処理するのが難しい場合があることです(1時間で十分だと思いますか?10分後にメモリが足りない場合はどうなりますか?有効期限が切れたレコード?)、および(2)レコードの2段階送信は、必要以上に複雑になる場合があります。

  3. クライアント側でプレビューロジックを移動します。


「これを永続化せず、what-ifのみを表示する」というヘッダーを送信するのはどうでしょうか。それはあなたに問題がなければ答えに編集します@ArseniMourzenko
marstato

1
@marstato:個人的には、私はその用途のHTTPヘッダーが特に好きではありません。他の人にとっては理にかなっているかもしれませんが、私の答えを編集しても大丈夫です。独自の回答を投稿することもできます。これにより、他の人がそれを投票できるようになります(そして、評価ポイントを獲得します)。
Arseni Mourzenko

私の場合、オプション1の方が適していると思います。したがって、プレビュー構成をPOSTすると、定義された各エンティティのプレビューエンドポイントを定義する代わりに、結果に変更が加えられます。理にかなっているようです。唯一のことは、技術的に言えば、サーバーを変更しないためにPOSTを使用していることです。私の場合、オプション3は実行不可能です。
エクストリームバイカー、モニカを復活させる

1
@PedroWerneckこれについて拡張できますか?オプション2は別のエンティティ(ドラフト構成)を定義し、それらと対話するステートレスな方法を提供するように思えます。
アンドリューは、モニカを復活させる

1
@PedroWerneckサーバーに設定を保存するのと同じようにステートフルです。したがって、アプリケーションはすでにあなたの観点からステートフルであり、この機能を追加するためのすべてのオプションもそうです。
jpmc26

10

RESTのさまざまなAPI呼び出しに特定のHTTP動詞を使用するポイントは、既存のHTTPメカニズムと期待を活用することです。

この場合にGETを使用すると、両方に反するようです。

A.クライアントは、GETで本文を含める必要がありますか?予想外

B.サーバーは、本文に応じてgetに対して異なる応答を返しますか?仕様とキャッシングの仕組みを破る

RESTfulな質問に苦労している場合、私のルールは自問することです。

「これは、すべてにPOSTを使用するよりも優れていますか?」

すぐに明らかなメリットがない限り、Just Use POST Stupid(JUPS)戦略を使用します



@Ewan ...これが実用的なアプローチであるかどうかに関係なく...すべてにPOSTを使用している場合、実際にはRESTfulではないことに注意する必要があります。
アレンフ

1
まあ、すべてのメソッドに対してPOSTが適切な選択でない限り。また、適用できる客観的なルールがあるわけではなく、ガイドラインにすぎないものの主観的な解釈を主張しているだけです。
ユアン

6

サーバーに「これを永続化せず、実行した場合の結果のみを表示する」ことを示すヘッダーを送信できます。例えば

POST /api/config HTTP/1.1
Host: api.mysite.com
Content-Type: application/json
Persistence-Options: simulate

{
   "config": {
      "key": "value"
   }
}

サーバーが応答できるもの:

HTTP/1.1 200 OK
Persistence-Options: simulated
Content-Type: application/json

-- preview --

DBで作業単位ベースのO / RMおよび/またはリクエストごとのトランザクションを使用する場合、特定のエンドポイントでの作業を必要とせずに、すべてのエンドポイントにこの機能を簡単に実装できることに注意してください。 、コミットする代わりにトランザクション/作業単位をロールバックします。



@PeterRaderの良い点は、削除X-
-marstato

どういたしまして。シミュレーション中のエンティティは「シミュレーション中」として表されるべきだと思いますか?
ピーターレーダー

番号; それがシミュレーションのポイントですよね?ヘッダー値も可能ですnoneが、それは-私の好みでは- POSTメソッドの性質と矛盾しすぎます。
-marstato

2

これを検索と同じように扱うことをお勧めします。/api/config/preview新しいプレビューを作成するPOSTエンドポイントを設定します。次にapi/config、現在の構成を編集するか、単に構成全体を置き換えるかによって、PUTまたはPATCHエンドポイントをセットアップします(前者の場合は、作成したばかりのプレビューを送信します)。


0

他の良い答えと一緒に、別のオプションは上記のような設定を投稿し、ロールバックプロセスも利用可能にすることができます。アジャイル手法と同様に、よりきめ細かく、再現性があり、テスト済みの手順を用意することで、変更を怖がらないほうが良いと思います。これにより、必要に応じてバックアップが提供され、アプリケーションに応じてリスクがほとんどまたはまったくなくなります。

繰り返しますが、システム全体に影響する構成エラーがある場合は、より積極的に処理する必要があります。その場合は、サーバーまたはクライアントの観点から、その時点での変更のプレビューに努力を払わないでください。このプレビュー機能の開発コストがどのように高くなるかはわかりますが、ユースケースでは、独自の一連の異なる手順に従ってテストを行う必要があります。


0

RFC6648は新しいX-コンストラクトを非推奨にしているため、新しいヘッダーフィールドを送信するというアイデアに反対する必要があります。RESTはアーキテクチャスタイルであり、私たちが話しているのはRESTfulですが、現時点ではそれを無視します。

RESTは代表(およびシミュレーションには現実の表現がない)およびステートフル(およびシミュレーションはコミットされるまで状態ではない)であるため、シミュレーションスコープのような新しいスコープが必要です。ただし、シミュレーションにはシミュレーションのプロセスが含まれますが、ステートフルとは、シミュレーションの理想的な解決策である定常状態、つまりエミュレーションを意味するため、シミュレーションではなくエミュレーションと呼ぶ必要があります。そのため、URLでエミュレーションと呼ぶ必要があります。これも良い解決策かもしれません:

GET  /api/emulation - 200 OK {first:1, last:123}
POST /api/emulation/124 - 200 OK
GET  /api/emulation/124/config - 200 OK {config:{tax:8}}
PUT  /api/emulation/124/config {config:{tax:16}} - 200 OK {config:{tax:16}}
GET  /api/emulation/124/items - 200 OK [first:1, last: 3000]
GET  /api/emulation/124/items/1 - 200 OK {price:1.79, name:'Cup'}
--- show emulation ---
--- commit emulation ---
PUT /api/config {config:{tax:16}}
DELETE /api/emulation/124 - 200 OK

別のアプローチは、あなたがたくさんHTML / JavaScriptをクライアントが生成することからの要求の持つ気づいたかもしれません....がありますあまりにも多くのリクエストを(見たのと同じ時間に17程度の要求の限界に達したものを、このページを)。RESTの使用法を交換し、不完全なオブジェクト状態を配信する代わりに、リッチなユーザー固有のページ状態を配信できます。例:

GET /user/123/config - 200 OK {user:'Tim', date:3298347239847, currentItem:123, 
                  roles:['Admin','Customer'], config:{tax:16}, unsavedChanges:true, ...}

敬具

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.