web-dev-qa-db-ja.com

REST AP​​I-単一のリクエストで一括作成または一括更新

BinderDocが独立していることを意味する関連付け関係を持つ2つのリソースDocBinderがあると仮定しましょう。 DocBinderに属する場合と属さない場合があり、Binderは空の場合があります。

ユーザーがDocsのコレクションを送信できるREST AP​​Iを設計する場合は、IN A SINGLE REQUEST、次のように:

{
  "docs": [
    {"doc_number": 1, "binder": 1}, 
    {"doc_number": 5, "binder": 8},
    {"doc_number": 6, "binder": 3}
  ]
}

docsの各ドキュメントに対して、

  • docが存在する場合は、Binderに割り当てます
  • docが存在しない場合は、作成してから割り当てる

私はこれがどのように実装されるべきかについて本当に混乱しています:

  • 使用するHTTPメソッド
  • どの応答コードを返す必要がありますか?
  • これはRESTにも適格ですか?
  • URIはどのように見えますか? /binders/docs
  • バルクリクエストの処理。少数のアイテムがエラーを発生させ、他のアイテムはエラーを発生させる場合。どの応答コードを返す必要がありますか?一括操作はアトミックである必要がありますか?
73
norbertpy

POSTまたはPATCHメソッドを使用してこれを処理できると思うのは、彼らは通常このために設計しているからです。

  • POSTメソッドの使用は通常、リストリソースで使用される場合に要素を追加するために使用されますが、このメソッドのいくつかのアクションをサポートすることもできます。この回答を参照してください: RESTリソースコレクションを更新する方法 。入力のさまざまな表現形式をサポートすることもできます(配列または単一の要素に対応する場合)。

    この場合、更新を説明するためにフォーマットを定義する必要はありません。

  • PATCH methodを使用することも適切です。これは、対応するリクエストが部分的な更新に対応しているためです。 RFC5789によると( http://tools.ietf.org/html/rfc5789 ):

    Hypertext Transfer Protocol(HTTP)を拡張するいくつかのアプリケーションでは、部分的なリソース変更を行う機能が必要です。既存のHTTP PUTメソッドは、ドキュメントの完全な置換のみを許可します。この提案は、既存のHTTPリソースを変更する新しいHTTPメソッドPATCHを追加します。

    この場合、部分的な更新を記述するためにフォーマットを定義する必要があります。

この場合、POSTPATCHは非常に似ていると思います。これは、各要素に対して行う操作を実際に記述する必要がないためです。送信する表現の形式に依存すると言うでしょう。

PUTのケースは少し明確ではありません。実際、メソッドPUTを使用するときは、リスト全体を提供する必要があります。実際のところ、リクエストで提供される表現は、リストリソースの表現に置き換わります。

リソースパスに関して2つのオプションがあります。

  • ドキュメントリストのリソースパスの使用

この場合、リクエストで提供する表現でバインダーとドキュメントのリンクを明示的に提供する必要があります。

この/docsのサンプルルートを次に示します。

そのようなアプローチの内容は、メソッドPOSTの場合です。

[
    { "doc_number": 1, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 2, "binder": 4, (other fields in the case of creation) },
    { "doc_number": 3, "binder": 5, (other fields in the case of creation) },
    (...)
]
  • バインダー要素のサブリソースパスを使用する

さらに、サブルートを活用してドキュメントとバインダー間のリンクを記述することも検討できます。ドキュメントとバインダーの関連付けに関するヒントは、リクエストコンテンツ内で指定する必要はありません。

この/binder/{binderId}/docsのサンプルルートを次に示します。この場合、メソッドPOSTまたはPATCHを使用してドキュメントのリストを送信すると、ドキュメントが存在しない場合、ドキュメントを作成した後、ドキュメントに識別子binderIdを添付します。

そのようなアプローチの内容は、メソッドPOSTの場合です。

[
    { "doc_number": 1, (other fields in the case of creation) },
    { "doc_number": 2, (other fields in the case of creation) },
    { "doc_number": 3, (other fields in the case of creation) },
    (...)
]

応答に関しては、応答のレベルと返すエラーを定義するのはあなた次第です。ステータスレベル(グローバルレベル)とペイロードレベル(シンナーレベル)の2つのレベルがあります。また、リクエストに対応するすべての挿入/更新がアトミックである必要があるかどうかを定義するのはあなた次第です。

  • アトミック

この場合、HTTPステータスを活用できます。すべてがうまくいけば、ステータスは200になります。そうでない場合、提供されたデータが正しくない場合(たとえば、バインダーIDが無効)またはその他の場合、400などの別のステータス。

  • 非原子的

この場合、ステータス200が返され、何が行われ、最終的にエラーが発生するかを記述するのは応答表現次第です。 ElasticSearchの一括更新用のREST AP​​Iにはエンドポイントがあります。これにより、このレベルでいくつかのアイデアが得られます: http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/bulk.html

  • 非同期

非同期処理を実装して、提供されたデータを処理することもできます。この場合、HTTPステータスの戻り値は202になります。クライアントは、何が起こるかを見るために追加のリソースを引き出す必要があります。

終了する前に、OData仕様がnavigation linksという名前の機能を持つエンティティ間の関係に関する問題に対処していることにも注目したいと思います。おそらくあなたはこれを見ることができます;-)

次のリンクも役立ちます: https://templth.wordpress.com/2014/12/15/designing-a-web-api/

お役に立てばと思います、ティエリー

50

おそらく、複数のリソースを更新および作成する単一のリクエストがべき等である可能性は低いため、POSTまたはPATCHを使用する必要があります。

PATCH /docsを実行することは間違いなく有効なオプションです。特定のシナリオでは、標準のパッチ形式の使用が難しい場合があります。これについてはわかりません。

200を使用できます。 207-マルチステータス も使用できます。

これはRESTfulな方法で実行できます。私の意見では、キーは、更新/作成する一連のドキュメントを受け入れるように設計されたリソースを持つことです。

PATCHメソッドを使用する場合、操作はアトミックであると考えられます。つまり、207ステータスコードを使用せずに、応答本文で成功と失敗を報告します。 POST操作を使用する場合、207アプローチが実行可能です。どの操作が成功し、どの操作が失敗したかを通信するための独自の応答本文を設計する必要があります。標準化されたものを知りません。

33
Darrel Miller

PUTing

PUT /binders/{id}/docs単一のドキュメントを作成または更新し、バインダーに関連付けます

例えば。:

PUT /binders/1/docs HTTP/1.1
{
  "docNumber" : 1
}

PATCHing

PATCH /docs存在しない場合はドキュメントを作成し、バインダーに関連付けます

例えば。:

PATCH /docs HTTP/1.1
[
    { "op" : "add", "path" : "/binder/1/docs", "value" : { "doc_number" : 1 } },
    { "op" : "add", "path" : "/binder/8/docs", "value" : { "doc_number" : 8 } },
    { "op" : "add", "path" : "/binder/3/docs", "value" : { "doc_number" : 6 } }
] 

後で追加の洞察を含めますが、それまでの間は、 RFC 5789RFC 6902 、William Durand's Please。Don 't Patch Like a Idiot ブログエントリ。

17

私が取り組んだプロジェクトでは、「バッチ」リクエストと呼ばれるものを実装することでこの問題を解決しました。次の形式でjsonを受け入れたパス/batchを定義しました。

[  
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 1,
         binder: 1
      }
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 5,
         binder: 8
      }
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 6,
         binder: 3
      }
   },
]

応答のステータスコードは207(マルチステータス)で、次のようになります。

[  
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 1,
         binder: 1
      }
      status: 200
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         error: {
            msg: 'A document with doc_number 5 already exists'
            ...
         }
      },
      status: 409
   },
   {
      path: '/docs',
      method: 'post',
      body: {
         doc_number: 6,
         binder: 3
      },
      status: 200
   },
]

この構造にヘッダーのサポートを追加することもできます。バッチ内のリクエスト間で使用する変数であることが証明された有用なものを実装しました。つまり、あるリクエストからのレスポンスを別のリクエストへの入力として使用できます。

FacebookとGoogleには同様の実装があります。
https://developers.google.com/gmail/api/guides/batch
https://developers.facebook.com/docs/graph-api/making-multiple-requests

同じ呼び出しでリソースを作成または更新する場合は、場合に応じてPOSTまたはPUTを使用します。文書が既に存在する場合、文書全体を次のようにしますか?

  1. 送信したドキュメントに置き換えられます(つまり、リクエストで欠落しているプロパティは削除され、既存の上書きされます)?
  2. 送信するドキュメントとマージされます(つまり、リクエストで欠落しているプロパティは削除されず、既存のプロパティは上書きされます)?

代替1の動作が必要な場合はPOSTを使用し、代替2の動作が必要な場合はPUTを使用する必要があります。

http://restcookbook.com/HTTP%20Methods/put-vs-post/

人々がすでに提案したように、PATCHに行くこともできますが、APIをシンプルに保ち、不要な場合は余分な動詞を使用しないことを好みます。

9
David Berg