REST APIでPATCHまたはPUTを使用する必要がありますか?


274

次のシナリオに適した方法で残りのエンドポイントを設計したいと思います。

グループがあります。各グループにはステータスがあります。グループは、管理者がアクティブ化または非アクティブ化できます。

エンドポイントを次のように設計する必要がありますか

PUT /groups/api/v1/groups/{group id}/status/activate

または

PATCH /groups/api/v1/groups/{group id}

with request body like 
{action:activate|deactivate}

1
どちらも大丈夫です。ただし、JSON PATCH形式のRFC(tools.ietf.org/html/rfc6902)を確認してください。PATCHは、ペイロードのある種のdiff / patchドキュメントを取得することを期待しています(未加工のJSONはそれらの1つではありません)。
ジョーンWildt

1
@JørnWildtいいえ、PUTは恐ろしい選択です。何を置いているの?PATCHは唯一の賢明なオプションです。この場合、質問で提示されたPATCH形式を使用して、PUTメソッドを使用できます。PUTの例は間違っています。
thecoshman 2014年

3
1つ以上のプロパティをスタンドアロンリソースとして公開しても、クライアントがPUTを使用してGETおよび変更できるので問題はありません。しかし、はい、URLは/ groups / api / v1 / groups / {group id} / statusである必要があり、PUTで​​「アクティブ」または「非アクティブ」またはGETして現在の状態を読み取ることができます。
ジョーンWildt

3
:ここでPATCHが本当に使用すべきかの良い説明だwilliamdurand.fr/2014/02/14/please-do-not-patch-like-an-idiot
rishat

4
activate」は適切なRESTfulな構築ではありません。おそらくstatus「アクティブ」または「非アクティブ」に更新しようとしています。その場合.../status、本文に「アクティブ」または「非アクティブ」の文字列を使用してPATCHできます。または、ブール値をで更新しようとしている場合は、ブール値を本文にstatus.active.../status/active
含めて

回答:


328

PATCHここでは、既存のリソース(グループID)を更新するため、この方法が適切です。 リソース全体を置き換えるPUT場合にのみ使用してください。

部分的なリソース変更の詳細については、RFC 5789を参照してください。具体的には、PUTメソッドは次のように説明されています。

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


1
公平に言うと、リソースに文字列「activate」または「deactivate」をPUTできます。切り替える必要があるのは1つだけのようです(そのように思われる)ので、完全に置き換えることはそれほど大きな問題ではありません。また、(わずかに)小さなリクエストも可能です。
thecoshman 2014年

35
RFC 5789はまだ提案フェーズにあり、正式に承認されておらず、現在「イラータが存在する」というフラグが付けられていることに注意することが重要です。この「ベストプラクティス」は非常に議論されており、技術的にはPATCHはまだHTTP標準の一部ではありません。
fishpen0

4
数年後のちょうど私の2セント:ステータス自体をリソースと見なすことができます。そうであれば、/ statusに対してPUTを使用すると、技術的にはそのエンドポイントでステータスリソースを置き換えることになります。
Jono Stewart

3
それが「the」RFCであるとしても、私はあえてドキュメントに対して議論するでしょう。ドキュメントには、PATCHを使用してリソースの一部のみを変更する必要があると記載されていますが、PATCHメソッドが非べき等メソッドとして定義されているという重要なことは省略されています。どうして?リソース全体の更新/置換を考慮してPUTメソッドが作成された場合、その目的がリソースの一部を更新するだけであるのに、PATCHメソッドがPUTのようなべき等メソッドとして作成されなかったのはなぜですか?私には、 "a = 5"(PUT)と "a = a + 5"(PATCH)のように、更新のべき等性の違いのように見えます。どちらもリソース全体を更新できます。
Mladen B.

179

REST のRはリソースを表します

(Representationalを表すため、これは正しくありませんが、RESTでのリソースの重要性を覚えておくことは良いトリックです)。

についてPUT /groups/api/v1/groups/{group id}/status/activate:「アクティベート」を更新していません。「アクティブ化」はものではなく、動詞です。動詞は決して良いリソースではありません。経験則:アクション(動詞)がURLにある場合、おそらくRESTfulではありません

代わりに何をしていますか?グループのアクティブ化を「追加」、「削除」、または「更新」するか、または必要に応じて、グループの「ステータス」リソースを操作します。個人的には、「アクティベーション」を使用します。これは、「ステータス」の概念よりも曖昧さが少ないためです。ステータスの作成は曖昧ですが、アクティベーションの作成はそうではありません。

  • POST /groups/{group id}/activation アクティベーションを作成(または作成の要求)します。
  • PATCH /groups/{group id}/activation既存のアクティベーションの詳細を更新します。グループにはアクティベーションが1つしかないため、どのアクティベーションリソースを参照しているかがわかります。
  • PUT /groups/{group id}/activation古いアクティベーションを挿入または置換します。グループにはアクティベーションが1つしかないため、どのアクティベーションリソースを参照しているかがわかります。
  • DELETE /groups/{group id}/activation キャンセルするか、アクティベーションを削除します。

このパターンは、グループの「アクティブ化」が、支払いの実行、メールの送信などの副作用を持っている場合に役立ちます。POSTとPATCHだけがこのような副作用を引き起こす可能性があります。たとえば、アクティベーションを削除して、たとえばメールでユーザーに通知する必要がある場合、DELETEは正しい選択ではありません。その場合、あなたはおそらくしたいの不活性化、リソースを作成しますPOST /groups/{group_id}/deactivation

この標準契約により、クライアント、およびクライアントとあなたの間のすべてのプロキシとレイヤが非常に明確になり、再試行しても安全な時期とそうでない時期がわかるため、これらのガイドラインに従うことをお勧めします。クライアントが不安定なwifiのどこかにあり、そのユーザーが「非アクティブ化」をクリックすると、次のようにトリガーされますDELETE。それが失敗した場合、クライアントは、404、200、または処理できる他の何かを取得するまで、単純に再試行できます。しかし、それがトリガーされるPOST to deactivationと、再試行しないことがわかります。POSTはこれを意味します。
すべてのクライアントが契約を結んでいます。これにより、HTTPライブラリがバックエンドへの呼び出しを再試行し続けたという理由だけで、「グループは非アクティブ化されました」という42通の電子メールの送信を防ぐことができます。

単一の属性の更新:PATCHを使用する

PATCH /groups/{group id}

属性を更新したい場合。たとえば、「ステータス」は、設定可能なグループの属性である可能性があります。「ステータス」などの属性は、多くの場合、値のホワイトリストに限定するのに適した候補です。例では、未定義のJSONスキームを使用しています。

PATCH /groups/{group id} { "attributes": { "status": "active" } }
response: 200 OK

PATCH /groups/{group id} { "attributes": { "status": "deleted" } }
response: 406 Not Acceptable

副作用なしでリソースを置き換えるには、PUTを使用します。

PUT /groups/{group id}

グループ全体を置き換えたい場合。これは、必ずしもサーバーが実際に新しいグループを作成し、古いグループを破棄することを意味するわけではありません。たとえば、IDは同じままである可​​能性があります。しかし、クライアントのために、これは何PUTであることができ、クライアントは、彼は、サーバーの応答に基づいて、全く新しいアイテムを取得しなければならないと仮定:意味します。

クライアントは、PUTリクエストの場合、常にリソース全体を送信し、新しいアイテムを作成するために必要なすべてのデータを持っている必要があります。通常、POST作成と同じデータが必要です。

PUT /groups/{group id} { "attributes": { "status": "active" } }
response: 406 Not Acceptable

PUT /groups/{group id} { "attributes": { "name": .... etc. "status": "active" } }
response: 201 Created or 200 OK, depending on whether we made a new one.

非常に重要な要件は、PUTべき等であることPATCHです。グループの更新(またはアクティブ化の変更)時に副作用が必要な場合は、を使用する必要があります。したがって、更新の結果、たとえばメールが送信される場合は、を使用しないでくださいPUT


3
これは私にとって非常に有益でした。"このパターンは、グループの"アクティブ化 "に副作用がある場合に役立ちます"-OPの初期エンドポイントとは対照的に、アクションに副作用がある場合にこのパターンが役立つ理由
Abdul

1
@アブドゥル、パターンは多くの理由で有用ですが、副作用に関しては、クライアントがアクションにどのような影響を与えるかが非常に明確である必要があります。たとえば、iOSアプリがアドレス帳全体を「連絡先」として送信することを決定した場合、連絡先の作成、更新、削除などにどのような影響があるかを非常に明確にする必要があります。たとえば、すべての連絡先の大量メール送信を回避するため。
16

1
RESTfullでは、PUTはエンティティのIDを変更することもできます-たとえば、並列リクエストが失敗する原因となる可能性があるPrimaryKey ID。(たとえば、エンティティ全体を更新するには、いくつかの行を削除して新しい行を追加する必要があるため、新しいエンティティを作成する必要があります)PATCHがこれを実行できないようにする必要がある場合、他の「アプリケーション」に影響を与えることなくPATCHリクエストを無制限に許可
Piotr Kula

1
非常に役立つ答え。ありがとう!Lukeの回答と同じように、コメントも追加します。PUT/ PATCHの違いは、全体/部分的な更新だけではなく、べき等でもあります。これは間違いではなく、意図的な決定であり、HTTPメソッドの使用を決定するときに、これを考慮に入れる人は多くないと思います。
Mladen B.

1
@richremerサービスは、モデルと同様に、内部的な抽象化です。RESTエンドポイントとORMモデル、またはデータベーステーブル間で1対1の関係を要求するのは不十分な抽象化であるのと同様に、サービスを公開することは抽象化が不十分です。外部、つまりAPIは、ドメインモデルと通信する必要があります。それらを内部的に実装する方法は、APIには関係ありません。APIを変更することなく、ActivationServiceからCQRSベースのアクティベーションフローに自由に移行できます。
2018年

12

リソース「グループ」には多くのプロパティがあるため、PATCHの使用をお勧めしますが、この場合は、アクティベーションフィールドのみを更新しています(部分的な変更)

RFC5789(https://tools.ietf.org/html/rfc5789)によると

既存のHTTP PUTメソッドは、ドキュメントの完全な置換のみを許可します。この提案では、既存のHTTPリソースを変更するために、新しいHTTPメソッドPATCHを追加します。

また、詳しくは

PUT要求とPATCH要求の違いは、サーバーが囲まれたエンティティを処理
してRequest-URIで識別されるリソースを変更する方法に反映されます。PUT要求では、囲まれたエンティティーは、
起点サーバーに保管されているリソースの変更バージョンであると見なされ、クライアントは保管されているバージョンの
置き換えを要求しています。ただし、PATCHでは、囲まれたエンティティに、現在
オリジンサーバーにあるリソースを変更して新しいバージョンを作成する方法を説明する一連の指示が含まれています。PATCHメソッドは、Request-URIによって識別されるリソース
に影響します。また、他のリソースに副作用がある場合もあります。つまり、新しいリソース

PATCHを 適用することにより、作成、または既存のものを変更できます。

[RFC2616]のセクション9.1で定義されているように、PATCHは安全でもべき等でもありません。

クライアントは、PUTで​​はなくPATCHをいつ使用するかを選択する必要があります。たとえば
、パッチドキュメントのサイズが
PUTで使用される新しいリソースデータのサイズより大きい場合、
PATCHの代わりにPUTを使用することは理にかなっています。POSTはさまざまな方法で使用され
、サーバーが選択した場合にPUTおよびPATCHのような操作を含めることができるため、POSTとの比較はさらに困難です。
操作がRequest- URIで識別されたリソースを予測可能な方法で変更しない場合、PATCH
またはPUT ではなくPOSTを検討する必要があります。

PATCHの応答コードは

応答にはメッセージ本文(200コードの応答の場合)が含まれていないため、204応答コードが使用されます。他の成功コードも使用できることに注意してください。

thttp://restcookbook.com/HTTP%20Methods/patch/も参照してください

警告:PATCHを実装するAPIは、アトミックにパッチを適用する必要があります。GETから要求されたときにリソースがハーフパッチされることはあり得ません。


7

RESTアーキテクチャスタイルを使用してAPIを設計する必要があるので、リソースとして公開するのに十分重要な概念を決定するために、ユースケースを検討する必要があります。グループのステータスをサブリソースとして公開することにした場合は、グループに次のURIを与え、GETメソッドとPUTメソッドの両方のサポートを実装できます。

/groups/api/groups/{group id}/status

修正のためのPATCHに対するこのアプローチの欠点は、グループの複数のプロパティをアトミックおよびトランザクションで変更できないことです。トランザクションの変更が重要な場合は、PATCHを使用してください。

ステータスをグループのサブリソースとして公開することにした場合、それはグループを表すリンクになります。たとえば、エージェントがグループ123を取得してXMLを受け入れる場合、応答の本文には次のものが含まれます。

<group id="123">
  <status>Active</status>
  <link rel="/linkrels/groups/status" uri="/groups/api/groups/123/status"/>
  ...
</group>

ハイパーリンクは、RESTアーキテクチャスタイルのアプリケーション状態条件のエンジンとしてハイパーメディアを満たすために必要です。


0

私は通常、activate/ deactivateサブリソース(Linkヘッダーでとリンクされているrel=service)のような、少し単純なものを好みます。

POST /groups/api/v1/groups/{group id}/activate

または

POST /groups/api/v1/groups/{group id}/deactivate

コンシューマーにとって、このインターフェースは非常にシンプルであり、個別のリソースとして「アクティベーション」を概念化することに煩わされることなくRESTの原則に従います。


0

このような動作を実装するための1つの可能なオプションは、

PUT /groups/api/v1/groups/{group id}/status
{
    "Status":"Activated"
}

そして、明らかに、誰かの必要性は、それを無効にする場合は、PUT必要がありますDeactivated JSONでステータスを。

大量のアクティブ化/非アクティブ化が必要な場合PATCH、ゲームにステップインできます(正確なグループではなく、groupsリソース用:

PATCH /groups/api/v1/groups
{
    { “op”: “replace”, “path”: “/group1/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group7/status”, “value”: “Activated” },
    { “op”: “replace”, “path”: “/group9/status”, “value”: “Deactivated” }
}

一般的に、これは@Andrew Dobrowolskiが示唆するアイデアですが、正確な実現には若干の変更があります。

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