web-dev-qa-db-ja.com

POST for REST APIの更新に使用しますか?

しばらくの間、REST APIリソースを更新するためにPUTまたはPATCHを使用しました。多くのPUT/PATCH呼び出しを使用した後、POSTで「更新」も実行できることに気付きました。

これは、状況を説明できれば非常に単純化された例です。リソースを持つエンドポイント/ api/cars/dealers/1があります

{
  "id": 1,
  "dealer_name": "Audi Atlanta",
  "year_opened": 2010,
  "contact_persons": [
    {
      "contact_person_type": "main_contact",
      "contact_person_name": "Mike Smith"
    },
    {
      "contact_person_type": "billing_contact",
      "contact_person_name": "Luke Johnson"
    }
  ]
}

RESTこのリソースをPOSTなどで更新すると、APIガイドラインに違反します。

{
  "contact_to_change": "main_contact",
  "contact_name": "John Smith"
}

の代わりに

{
  "id": 1,
  "contact_persons": [
    {
      "contact_person_type": "main_contact",
      "contact_person_name": "Mike Smith"
    }
  ]
}

またはPUTによる完全なリソース更新の代わりに

ペイロードの構造がリソース自体の構造とはまったく異なることに注意してください。これは、同じボディ構造に従うrawリソースの更新を行うよりもはるかに簡単な場合があります。

この方法で、現時点では見られない問題が発生する可能性はありますか?

2
John

POSTを使用してリソースを更新できますが、更新するリソースと同じURLを使用することはできません。したがって、PUT/PATCHで使用するURLが/api/cars/dealers/1の場合、 PATCHリクエストの場合と同じように、POSTボディとリクエストを送信するための/api/cars/dealerupdatesが必要です。

このように、/api/cars/dealers/または/api/cars/dealers/1の下に新しいエンティティを作成していないことは明らかです。作成されるのは、リクエスト内のエンティティにある時点で適用される新しい更新エンティティです。それを確認するもう1つの方法は、GETリクエストを/api/cars/dealerupdatesに送信すると、処理された更新のリストを提供できることです。

3
imel96

yes, you can use POST for updatesyes, it's ok using POST for updatesの間には微妙な違いがあります。

技術的には可能ですが、大丈夫ではありません。まれな制約に対処する場合、またはRPC Webインターフェイスを実装する場合を除きます。

なぜ大丈夫ではないのですか?その理由は、他の2つの回答とコメントにあります。それは奇妙だ。ややこしい。

混乱していますか?誰のため?一方では、HTTP動詞に精通していて、APIを操作する必要がある人のために。一方、HTTPクライアントは非常に特殊な方法で動作するように実装されています。 OK、あなたのアイデアはほとんどのHttpクライアントで機能しますが、突然クライアントが期待どおりに機能しなくなった場合、誰かをより困難にしてしまいます。

リフレクションを共有させてください。多くの場合、私たちは"happy ideas"と呼んでいます。 幸せなアイデア私たちには多くの意味があります。私たちは、明白で見事なものであり、それらは機能し、大丈夫です。

問題は、私たちが誤った前提や根拠、知識の欠如、または絶対的な無知のもとで彼らに到達した場合です。

HTTPのセマンティクスに精通していて、APIがおかしなWTF時間を発生させたくない場合は、更新にPOSTを使用しません。他の仕事それは不必要な認知的負担を負います。

この方法で、現時点では見られない問題が発生する可能性はありますか?

言いにくい。それは、幸せなアイデアがどのように物事を複雑にするかに依存します。あなたがインターネットで見知らぬ人にこの質問をしなければならないなら、それは良い考えではありません。最初にHTTPを学び、それに慣れます。その後、必要に応じて安全にねじります。

1
Laiv

メッセージのセマンティクスに少し依存します

a POST to/api/cars/dealers/1/updateは、新しい更新リクエストを送信しているので問題ありません(また、更新リクエストが後で)

/ api/cars/dealers/1/updateに異なる構造化更新を投稿することもできます。これは、クエリがコマンド(更新)から分離され、コマンドがそれ自体のエンティティーのように構造化されるCQRSのようなアーキテクチャーとより調和します。

しかし、一般的に言えばPOSTは、新しい連絡担当者(/ api/cars/dealers/1/contactへの投稿)または新しい更新リクエストのいずれかを作成する必要があります。

1
Batavia

REST APIという用語は、APIはプログラマーや開発者が使用する必要があるものであり、呼び出されていくつかのビジネスプロセスをトリガーするものであるため、実際にはRPC風の考え方全体に大きく依存しています。 APIとの対話方法に関する開発者向けのガイドラインを多かれ少なかれマークし、API自体の真実となり、APIがドキュメントに固執する必要があるため、APIが将来の進化を妨げるいくつかの豪華なドキュメントが同梱される場​​合があります。もちろん、ドキュメントは更新できます。ただし、これにより、APIのバージョン管理と、バージョンNをサポートするが将来的にはMをサポートしないクライアントにサービスを提供する方法に関する質問が発生します。これらの問題は、RPC(SOAP、Corba、RMIなど)から数十年前からわかっています。これは、RESTとは異なります。

フィールディングは、RESTを建築スタイルとして定義しました。 Robert C. "Uncle Bob" Martinによれば、 アーキテクチャはインテント に関するものであり、RESTの背後にあるインテントはサーバーからクライアントへの分離です。後者のクライアントがクライアントを壊すことを恐れずに将来自由に進化できるようにします。デカップリングを実現するために、クライアントとサーバーは特定の一連の制約に準拠する必要があります。これはオプションではありませんが、準拠する必要があります。カップリングを導入するのは簡単すぎます。そのため、WWWを除いて、世界中にまだ正確な実装が十分にないのです。

RESTは基本的にWebを成功に導いた概念を再利用し、それが歴史的にRPC駆動であり、したがって密結合されていたアプリケーションドメインに適用しました。カップリングが原因で、サービスが何らかの方法で変更されたときに多くのサービスが突然動作を停止したため、これは通常、いわゆる「REST API」すべてに当てはまります。

WWWを詳しく見ると、クライアントがリンクを使用して新しい状態を取得し、HTMLフォームを使用してデータをサーバーに送信していることに気付く場合があります。このフォームは、サーバーに送信されたリクエストがどのように見える必要があるかをクライアントに教えます。これには、データを送信するエンドポイントが含まれており、サーバーに送信する前にデータをフォーマットするためのメディアタイプだけでなく、使用するメソッドも含まれている場合があります。特定のハイパーテキスト対応メディアタイプ(HAL JSONなど)は存在しますが、ハイパーテキスト対応フォームのサポートはまだ初期段階にあります。利用可能なドラフトがいくつかありますが、まだ本当に広くサポートされているものはまだありません。

多くのPUT/PATCH呼び出しを使用した後、「更新」はPOSTでも実行できることに気付きました

...

このリソースをRESTで更新すると、POST APIガイドラインに違反しますか?.

場合によって異なりますが、とにかくREST APIガイドラインとは何ですか?それらは標準化されていないので、これを述べるかもしれないし、もう一つは正反対の状態を言うかもしれない。どちらが本当ですか?これらのガイドラインのほとんどは、RPCの匂いがあるため、URI内に動詞が存在すべきではないと述べています。 REST環境では実際には、URIの形式はまったく重要ではありません。リクエストを送信するために使用するだけです。サーバーは基本的に自由にURIを変更できるため、クライアントはURIを分析しないでください。コンテンツタイプネゴシエーションに依存して表現を取得する代わりに、特定のエンドポイントが特定の types を返すことを検討する多くのAPI固有のクライアントへの道がすでにあります実際に処理および処理できるデータのURI自体は重要な部分ではありません。リンクの関係や、標準化されたメディアタイプで定義されている人間が読めるテキストなどの付随データの方が重要です。私たち人間も、Cookieの情報と暗号化されたパラメータを含む実際のリンク自体ではなく、リンクの内容を要約した人間が読めるテキストを読むことを好みます。したがって、従うべきガイドラインには注意が必要です。

POSTを使用してデータを更新することは、一般的にRESTの原則に反する場合、大きな従兄弟であるRESTの背後にあるアイデア全体が由来するWWWも原則に準拠しませんRESTは意味します。ほとんどの場合Webページで交換される事実上の標準ドキュメント形式であるHTMLは、POSTおよびGETのみをサポートします。 HTTPはDELETE、PATCH、PUTまたはその他の その他の標準化されたHTTP操作 を受け入れても問題ありませんが、HTMLはこれらの2つのみをサポートすることを決定し、手元にあるすべてのタスクを解決できます。

RFC 7231 は、POSTを、特に以下のセマンティクスの場合に使用する必要がある汎用ツールキットとして使用できるように定義します他の操作は現在のタスクに適合しません。ただし、これはPOSTのみを使用する必要があるという意味ではありません。つまり Jim Webber が指摘したように、クライアントにべき等の約束があるため、金融取引を扱う場合はPUTを使用する必要があります。 2011年から話を戻します。最近はすべてが非常に高速でローカルに近いように見えますが、ネットワーク障害やその他の一時的なエラーが発生する可能性のあるリモートインフラストラクチャを扱っています。ネットワーク障害が発生した場合、クライアントがリクエストを盲目的に再送できるか、それともさらなる処理につながるかをクライアントに知らせることは良いことです。そのような約束の周りに特定の 作成パターン も進化しました。

RESTアーキテクチャの主な前提は、サーバーがクライアントに次に何ができるかを教えることです。一連のオプションは、そのリンクのコンテンツに関心がある場合に呼び出すリンクの形式でクライアントに提供されます。リンク関係やその他の付随データに基づいて、クライアントはその情報を取得することに関心があるかどうかを判断する必要があります。サーバーは、フォーム表現をクライアントに送信し、含まれている要素の アフォーダンス に基づいて、クライアントが知っている追加の入力が必要であることをクライアントに教えることができます。いくつかの外部ドキュメントを必要とせずに、サーバーが期待し、それに応じて動作できるもの。これが基本的にHATEOASのすべてです。クライアントにオプションを与え、サーバーが期待することを教える。ジムウェバーによると、基本的には ドメインアプリケーションプロトコル を実装し、リンクとフォーム入力要求を介してクライアントが進行する有限状態マシンに基づいています。

HTMLでわかるように、メディアタイプは、使用可能なHTTP操作をさらに指定または制限する場合があります。多目的の一般的なメディアタイプの場合、これはおそらく標準ではありませんが、HTMLなどの特定のメディアタイプでは可能です。また、将来的に相互運用性の問題に遭遇したくない場合は、これらに準拠する必要があります。

この方法で、現時点では見られない問題が発生する可能性はありますか?

上記のように、特定のHTTP操作は、異なるセマンティクスを提供し、クライアントに約束します。つまりPUTリクエストでネットワークの問題が発生した場合、クライアントは、リクエストがべき等の方法で処理され、同じ結果につながることを期待しているため、深く考えずにリクエストを再送信できることを知っています。リクエストは1回または複数回受信されました。ただし、POSTを使用すると、要求がサーバーに到達しなかったか、その要求の応答が途中で失われたかどうかをクライアントが確認できません。そのような場合、クライアントはリクエストを再送信することで何が発生するかを保証できません。ジムウェバーのビデオで私がリンクした彼は、そのような場合にPUTを使用する理由を明確に説明しています。技術的にはPOSTを処理してサーバー側で常にべき等に動作し、PUTはべき等に動作しないようにすることができます。これはサーバーの問題であるため、クライアントには関係ありません。これは、GETメソッドの呼び出しを介してアイテムXの注文10000供給を公開し、GoogleがそのURIを取得して呼び出す場合と同じです。クライアントは、このようなずさんな実装に対して責任を負うことはできません。

RFC 7231 は安全に関して明示的に述べています。

この安全なメソッドの定義は、潜在的に有害な動作、完全に読み取り専用ではない動作、または安全なメソッドの呼び出し中に副作用を引き起こす動作を実装に含めることを妨げません。ただし、重要なことは、クライアントが追加の動作を要求しておらず、その動作に対して責任を負うことができないことです。

要するに、要するに、POSTをPUTの代わりとして使用できますか?はい、できます。しかし、それを盲目的に使用すべきではありません。特にデータがべき等である必要がある場合は、POSTの代わりにPUTを使用する必要があります。技術的にPUTと同じようにPOSTを処理できますが、仕様がクライアントに与える約束は明確であり、これらに違反する場合、クライアントはあなたの過ちの責任を負わされませんでした。

0
Roman Vottner