web-dev-qa-db-ja.com

リソースを更新する正しいRESTfull方法

reportsのようなリソースがあるとします。すべてのレポートにはいくつかのデータを作成するための独自の設定が含まれているため、コレクションがあります。

すべてのレポートは定期的にその値を計算しますが、頻繁には計算しません。最も実際のデータを得るために、レポートを今すぐ再計算する可能性があります。

問題は、どのようなリクエストがそれを行うための最もRESTfullな方法になるかです。

最初の回答を得た後の詳細:

この「再計算」には比較的時間がかかります。したがって、多かれ少なかれ同期的に終了することができないため、これはGET要求にすることはできません。 APIクライアントの目的は、結果を取得することではなく、この更新プロセスを開始することです。

もう一つの例。人々のデータベースと比較的大きなフィルターのコレクションがあり、それぞれがいくつかの基準に基づいて人口統計を計算するとします。条件は次のとおりです。

  • これらのフィルターを再計算することは非常に高価です
  • いくつかのフィルターのみが実際に定期的に最新の計算を提供し、クライアントのみがどのフィルターを知っているか
  • クライアントは人々のテーブルに大規模な変更をもたらします。そのため、クライアントだけがそれがいつ発生し、いつ新しい計算を実行することが理にかなっているのかを知っています。
4
Stepan Stepanov

問題は、どのようなリクエストが最もRESTfullな方法になるかです。

したがって、あるURIにReportリソースがあります。たとえば、mysite.com/reports/343

このリソースは、いくつかの異なる状態である可能性があります。最新の状態である可能性があります。再生成が必要である可能性があります。

そのリソースの表現はこのようなものかもしれません

application/vnd.stepanov_report_long-v1 + json

{
  report_state: "not generating",
  report_data: [
     "John Doe": {age: 34},
     "Jane Doe": {age: 35},
     ...
     ...
     "Xan Doe": {age: 32}
 ]
}

あなたはこのような別の表現を持つこともできます

application/vnd.stepanov_report_short-v1 + json

{
  report_state: "not generating",
}

ほとんどの場合、クライアントはそのレポートの完全なデータに関心があります。これは、そのレポートの現在の状態の1つの表現です。

しかし、クライアントは、レポートが最新であるかどうか、またはレポートが再生成されているかどうかをクライアントに伝える表現に関心がある場合があります。この場合、クライアントはリソースを要求できます(Acceptヘッダーを使用した短い形式のバージョン)。その後、そのリソースを更新し、サーバーに新しいバージョンを送り返すことができます

リクエスト

GET mysite.com/reports/343
Accept: application/vnd.stepanov_report_short-v1+json

サーバーからの応答

{
    report_state: "not generating",
}

リクエストをサーバーに返す

PUT mysite.com/reports/343
Content-Type: application/vnd.stepanov_report_short-v1+json
{
    report_state: "generating"
}

(レポートの状態がクライアントによって変更されたことに注意してください)

サーバーは、クライアントがリソースを再生成の状態にしたことを認識します。この副作用として、サーバーは実際のデータを再生成します。

これにより、ドメイン固有のロジックを含むURIスキームの必要性が減ります。一般に、URIスキームをリソースに限定し、ドメイン固有のロジックを表現形式(つまり、コンテンツタイプ)に入れることをお勧めします。

1
Cormac Mulhall

If-None-Match または If-Unmodified-Since ヘッダーセットを使用してGET /reports/{id}を呼び出します。サーバーは、再計算が必要かどうかを判断します。そうでない場合は、304 NOT MODIFIEDを返します。もしそうなら、それは再計算し、レスポンスボディで新しいレポートを返します。

質問では注意が必要ですが、再計算には時間がかかります。例えば。 10分まで。したがって、リクエストは実際には同期できません。 「正しい結果を最新のものにしたい」のではなく、「このリソースを今すぐ最新のものにして後で取得したい」

その場合は、/report-updates/{id}などの新しいエンドポイントを作成します。 POST /report-updates/{id}を呼び出します。レポートが最新の場合は、304 Not Modifiedを返します。レポートを再計算する必要がある場合は、202 Acceptedを返します。現在のステータスと推定完了時間を含む応答本文を含めます。 /report-updatesへのGET呼び出しは、現在のステータス/完了時間で200 OKを返すか、Locationヘッダーを307 Temporary Redirectに設定して/reports/{id}を返します。

もう1つの選択肢は、クライアントに定期的にサーバーをポーリングさせることです。上記の条件付きヘッダーでGET /reports/{id}を使用します。常に200または304を返しますが、サーバーデータが最新でない場合は再計算を開始します。その後、すべてのクライアントが最新の計算を取得することが保証されます。

9
Eric Stein

読み取りについて:私の通常の答えは、いくつかのIDを使用して各「レポート」を追跡することです。例えば

GET /reports/{id}/latest is going to redirect to, say,
GET /reports/{id}/latest?asOf=2016-05-17T12:00:00%20-0500

これらのリソースは常に処理が完了したレポートを参照するため、実行されるのを待つことはなく、レポートの表現はキャッシュ可能です。

実際に更新を実行するプロセスでは、別のリソースを使用します。 Jim Webberが言うように、HTTPはあなたのアプリケーションではありません。ドキュメントを渡すことにより、プロトコルを実装するために使用します。

したがって、更新をスケジュールするコマンド(または状態の表現がhtmlの場合はPOST)をPUTします。それは次のようになるかもしれません:

PUT /reports/{id}/updates/your-guid-here-two-dollah

アプリケーションがその時点でレポートの更新をスケジュールする場合は、作成された201を返し、レポートプロセスの更新を確認する方法をクライアントに示すアプリケーションの状態を表します。レポートの準備ができた時点で、アプリケーションの状態の表現には、生成されたレポートへのリンクが含まれます。

レポートにSLA=レポートがある場合は、キャッシュを使用してゲームをプレイし、サービスに追加の負荷をかけずにクライアントが「更新」できることを確認できます。重要。

閲覧を推奨: REST in Practice Jim Webber-特に彼がRestbucksプロトコルの実装について議論するとき。

1
VoiceOfUnreason