web-dev-qa-db-ja.com

のHTTPレスポンスコード POST リソースがすでに存在する場合

クライアントがオブジェクトを保存できるようにするサーバーを構築しています。これらのオブジェクトは完全にクライアント側で構築され、オブジェクトの全存続期間にわたって永続的なオブジェクトIDを完備しています。

クライアントがPUTを使用してオブジェクトを作成または変更できるように、APIを定義しました。

PUT /objects/{id} HTTP/1.1
...

{json representation of the object}

{id}はオブジェクトIDなので、Request-URIの一部です。

さて、私はクライアントがPOSTを使ってオブジェクトを作成することを許可することも検討しています。

POST /objects/ HTTP/1.1
...

{json representation of the object, including ID}

POSTは "追加"操作を意味しているので、オブジェクトが既に存在している場合に何をすべきかわかりません。リクエストを修正リクエストとして扱うべきですか、それとも何らかのエラーコードを返すべきですか(どちらがいいですか)。

676
vmj

私の感情は409 Conflictであることが最も適切ですが、当然のことながらほとんど見られません。

リソースの現在の状態と競合しているため、要求を完了できませんでした。このコードは、ユーザーが競合を解決してリクエストを再送信できる可能性があると予想される状況でのみ許可されます。レスポンスボディは衝突の原因をユーザが認識するのに十分な情報を含むべきである[SHOULD]。理想的には、レスポンスエンティティは、ユーザーまたはユーザーエージェントが問題を解決するのに十分な情報を含むでしょう。ただし、それは不可能である可能性があり、必須ではありません。

競合は、PUT要求に応答して発生する可能性が最も高いです。たとえば、バージョン管理が使用されていて、PUTされているエンティティに、以前の(サードパーティの)要求によって行われたものと競合するリソースへの変更が含まれている場合、サーバーは409応答を使用して要求を完了できないことを示します。 。この場合、レスポンスエンティティはレスポンスContent-Typeで定義されたフォーマットで2つのバージョン間の違いのリストを含むでしょう。

840
Wrikken

RFC 7231 によると、 303他を参照 {を使用してもよいPOSTの処理結果が既存のリソースの表現と等価になる場合

72
Nullius

個人的にはWebDAVの拡張子422 Unprocessable Entityを使います。

RFC 4918に準拠

422 Unprocessable Entityステータスコードは、サーバーがリクエストエンティティのコンテンツタイプを理解しているため(つまり、415 Unsupported Media Typeステータスコードは不適切です)、リクエストエンティティの構文は正しい(したがって、400 Bad Requestステータスコードは不適切です)が、含まれているコンテンツを処理できませんでした。説明書.

67
Gareth

REST AP​​Iを作成しようとしている間、ゲームに遅れるかもしれませんが、私はこの意味論の問題につまずいた。

Wrikkenの答えを少し拡張するには、状況に応じて409 Conflictまたは403 Forbiddenのどちらかを使用できると思います。つまり、競合を解決して要求を完了するためにユーザーがまったくできない場合は403エラーを使用します。明示的にリソースを削除するためにDELETEリクエストを送信するか、何らかの可能性がある場合は409を使用します。

10.4.4 403禁止

サーバーは要求を理解しましたが、それを満たすことを拒否しています。承認は助けにならないでしょうし、要求は繰り返されるべきではありません。リクエストメソッドがHEADではなく、リクエストが満たされなかった理由をサーバが公表したい場合は、エンティティ内で拒否された理由を説明する必要があります。サーバーがこの情報をクライアントが利用できるようにしたくない場合は、代わりにステータスコード404(Not Found)を使用できます。

今日では、誰かが "403"と言ってパーミッションや認証の問題が頭に浮かぶが、その仕様では基本的にサーバーには実行しないように指示し、再度要求しないようにしている。じゃない。

PUT vs. POST...についてPOSTは、ユーザーがリソースの識別子を作成する手段がない、または作成すべきでない場合に、リソースの新しいインスタンスを作成するために使用されるべきです。 PUTは、リソースのIDがわかっているときに使用されます。

9.6 PUT

...

POSTとPUTリクエストの基本的な違いは、Request-URIの意味の違いに反映されています。 POST要求内のURIは、囲まれたエンティティを処理するリソースを識別します。そのリソースは、データ受け入れプロセス、他のプロトコルへのゲートウェイ、または注釈を受け入れる別のエンティティなどです。対照的に、PUTリクエストのURIはリクエストに同封されたエンティティを識別します - ユーザエージェントはどんなURIが意図されているか知っていて、サーバはリクエストを他のリソースに適用しようと試みてはいけません。サーバが要求が異なるURIに適用されることを望む場合、

それは301(永久に動かされた)応答を送らなければなりません;ユーザエージェントはそれからリクエストをリダイレクトするかどうかに関してそれ自身の決定をするかもしれません。

20
p0lar_bear

"302 Found"は私には論理的に思えます。そして RFC 2616 はそれがGETとHEAD以外の他の要求に対しても答えることができると言います(そしてこれは確かにPOSTを含みます)

しかしそれでも、訪問者はこの "Found"リソースを取得するためにRFCによってこのURLにアクセスし続けます。本物の "Found" URLに直接移動するには、 "303 See Other"を使用する必要がありますが、これは理にかなっていますが、次のURLをGETするための呼び出しを強制します。良い面では、このGETはキャッシュ可能です。

私は "303 See Other" を使用すると思います。私は私がボディで見つけられる「事」と答えることができるかどうか知らないが、私はサーバーへの1往復を節約するためにそうしたいと思う。

更新: RFCを読み直した後も、 存在しない "4XX + 303 Found"のコードが正しいはずです。しかし、 "409 Conflict"は既存の最良の回答コード (@ Wrikkenが指す)で、おそらく既存のリソースを指すLocationヘッダーを含みます。

13
alanjds

418を返すことについてはどうですか?

クライアントはすでにサーバー上に存在するエンティティを永続化するよう要求するので、サーバーはついに狂って彼が急須であると思い、418 I'm a teapotを返します。

参考文献:

13
рüффп

私はあなたがこれをすべきだとは思わない。

POSTは、ご存知のとおり、コレクションを変更するためのもので、新しい項目を作成するために使用されます。ですから、もしあなたがidを送ったら(それは良い考えではないと思います)、あなたはコレクションを修正するべきです、すなわちアイテムを修正するべきです、しかしそれは混乱します。

IDなしでアイテムを追加するために使用します。それはベストプラクティスです。

PUTリクエストの場合と同じように、(IDではなく)UNIQUE制約を取り込む場合は、409と応答できます。しかしIDではありません。

9
Alfonso Tienda

RESTについては、あなたはその特定のシステムの振る舞いについて決定を下さなければならないと思います。その場合、私は「正しい」答えがここで与えられるいくつかの答えのうちの1つになると思います。リクエストを停止して、続行する前にクライアントが修正する必要があると間違えたように動作させる場合は、409を使用します。競合がそれほど重要ではなく、リクエストを続行したい場合は、リダイレクトして応答します。見つかったエンティティへのクライアント。とにかく、適切なREST AP​​IがPOSTに続いてそのリソースのGETエンドポイントにリダイレクト(または少なくともロケーションヘッダーを提供)すべきだと思うので、この動作は一貫した経験を与えるでしょう。

編集:それはあなたがIDを提供しているのであなたはPUTを考慮すべきであることも注目に値する。それで、振る舞いは単純です:「私は今そこにあるものを気にしないで、このことをそこに置きなさい」。つまり、何もない場合は作成されます。何かがあればそれは置き換えられます。サーバがそのIDを管理するときはPOSTがより適切であると思います。 2つの概念を分けることは基本的にそれをどのように扱うかをあなたに教えます(すなわちPUTは冪等性であるのでペイロードが検証する限り常に働くべきです、POSTは常にIDの衝突があるなら409はその衝突を説明するでしょう)。

6
Sinaesthetic

それはすべて context についてであり、また誰がリクエストに重複しているかについて責任があります(サーバーまたはクライアントあるいは両方)

サーバーが だけ複製を指す場合 、4xxを見てください。

  • 400 Bad Request - 明らかなクライアント障害のためにサーバがリクエストを処理しない場合
  • 409 Conflict - サーバがリクエストを処理しないが、その理由はクライアントのせいではない
  • ...

暗黙の 重複の処理については、2XXを見てください。

  • 200 OK
  • 201作成済み
  • ...

サーバーが 何かを返すことが期待されている場合 、3XXを見てください。

  • 302見つかりました
  • 303他を見る
  • ...

サーバーが既存のリソースを指すことができる場合、それはリダイレクトを意味します。

上記の方法では不十分な場合は、応答の本文にエラーメッセージを用意することをお勧めします。

5

なぜ 202受け入れられない ?それはOKリクエスト(200秒)、クライアントエラーはありません(400秒)、それ自体です。

から 10ステータスコードの定義

「202受け入れられました。要求は処理のために受け入れられましたが、処理は完了しませんでした。」

...すでに存在しているので、完成する必要はありません。クライアントはそれがすでに存在していることを知りません、彼らは何も悪いことをしませんでした。

私は202を投げて、GET /{resource}/{id}が返していたものと同様の内容を返すことに傾いています。

5

私は422 Unprocessable Entityを使います。これはリクエストが無効だが問題が構文や認証にない場合に使われます。

他の答えに対する議論として、非4xxエラーコードを使用することはそれがクライアントエラーではないことを意味するでしょう、そしてそれは明らかにそうです。クライアントエラーを表すためにnon -4xxエラーコードを使用することはまったく意味がありません。

ここでは409 Conflictが最も一般的な答えであるように思われますが、仕様によると、これはリソースが既に存在し、それに適用している新しいデータが現在の状態と互換性がないことを意味します。たとえば、すでに取得済みのユーザー名を使用してPOSTリクエストを送信している場合、ターゲットリソースはまだ投稿されていないので、実際にはターゲットリソースと競合しません。保管されているリソースのバージョンと要求されているリソースのバージョンとの間に矛盾がある場合、これは特にバージョン管理のエラーです。たとえばクライアントが古いバージョンのリソースをキャッシュしていて、条件付きで有効ではなくなったその誤ったバージョンに基づいて要求を送信した場合など、その目的に非常に役立ちます。 「この場合、応答表現には、改訂履歴に基づいて差異をマージするのに役立つ情報が含まれている可能性があります。」そのユーザ名で別のユーザを作成する要求は処理不可能で、バージョン管理とは関係ありません。

レコードの場合、422は、すでに使用されている名前でリポジトリを作成しようとしたときにGitHubが使用するステータスコードでもあります。

5
Grant Gryczan

もう一つの可能​​性のある治療法は結局パッチを使用しています。 PATCHは、内部状態を変更するものとして定義され、追加に限定されません。

PATCHを使用すると、既存の項目を更新することで問題を解決できます。参照してください: RFC 5789:パッチ

4
Martin Kersten

208 - http://httpstatusdogs.com/208-already-reported についてはどうですか?それは選択肢ですか?

私の意見では、唯一のものがリソースの繰り返しである場合、エラーは発生しません。結局のところ、クライアント側にもサーバー側にもエラーはありません。

2

重複レコードの正しいコードをチェックしているときに、この質問につまずいた。

私の無知を許しなさいしかし私はなぜ誰もが明らかに「複数選択」または「あいまい」を言うコード「300」を無視しているのか理解していない

私の意見では、これはあなた自身の使用のための非標準または特定のシステムを構築するための完璧なコードになるでしょう。私も間違っている可能性があります。

https://tools.ietf.org/html/rfc7231#section-6.4.1

2
Hitin

おそらくそれは400 Bad Requestです

6.5.1。400不正な要求


400(Bad Request)ステータスコードは、クライアントエラーと見なされるもの(たとえば、不正な形式の要求構文、無効な要求メッセージのフレーミング、不正な要求など)が原因で、サーバーが要求を処理できないか処理できないことを示します。ルーティング)。

要求に重複した値(すでに存在する値)が含まれているため、それはクライアントエラーとして認識される可能性があります。次の試行の前にリクエストを変更する必要があります。
これらの事実を考慮することで、HTTP STATUS 400 Bad Requestとして結論付けることができます。

2
Mohammed Safeer