web-dev-qa-db-ja.com

POSTおよびPUTハンドラは404の飛行前チェックを行う必要がありますか?

リソースにGETを実装する場合、リソースが見つからない場合は404で応答するのが理にかなっています。 POSTおよびPUT動詞の場合、少し複雑です。

その場合に404で応答するには、なんらかの飛行前チェックを行う必要があります。最初にデータベースでSELECTを実行し、一致する行があるかどうかを確認します。ない場合は、404で応答します。ただし、同時ユーザーのため、次のUPDATE sqlコマンドがすべての行に影響するという保証はありません。

とにかくリクエストが正常に処理される保証がない場合でも、REST APIでリソースの飛行前チェックを実装することは良い方法ですか?

2

結局のところ、あなたの質問はHTTP動詞の一般的な誤用にルーツがあると思います。

[〜#〜]プット[〜#〜]

RDBMでPUTUPDATEと同等にすることは一般的ですが、実際には「UPSERT」に似ています(つまり、存在しない場合は更新または挿入)。

したがって、別の回答に関するコメントでRobert Harveyが指摘したように、一見すると、更新されているリソースの種類(またはその親)を理解している場合に、見つからない404を返すことは意味がありません。次のURIを検討してください。

https://domain.com/{root}/{parent}/{child}

したがって、上記の場合、存在しないPUTまたはrootに対してparentを実行しようとした場合に404​​を返すことは理にかなっており、これらが修正されている場合は、まともなフレームワークが何をするか。 childが存在しない場合は、作成できます。ただし、いくつかの注意点があります。

さておき、クライアントが上記のようにPUTでリソースを作成することを許可するとします。しかし、複数のユーザーが同じルート/親パスから作成できると仮定しましょう。あるユーザーが別の(関連のない)ユーザーが作成したリソースにPUTしようとした場合はどうなりますか?ここには2つの可能性があります。それらは、新しいリソースを作成しようとするなどのエラーを発生させたか、意図的に何か悪いことを試みています。どちらの場合も、それを許可したくないので、403(禁止)エラーを返すことができます。ただし、そのパスが存在するかどうかについての情報を提供したくない場合は、404を返すこともできます。しかし、パスが存在しないときに201のみを返すと、再び情報が漏洩します。これは、このようなシナリオで404を使用できることを示唆しています。それはまた、そのようなスキームが良い考えであるかどうかに疑問を投げかけます。ユーザー/クライアント識別子をパスの一部にすると、そもそもそのような偶発的な衝突を回避できます。この方法で対処することは意味がないとは言えませんが、クライアントのエラーシナリオを区別することが難しくなる可能性があります。

しかし、ユーザーがPUTを使用して独自のリソースを作成できないようにするにはどうすればよいですか?

問題ありません。あなたがする必要はありません。仕様にPUTが作成または更新できると記載されているからといって、それらがPUTで送信するURIの作成を強制されるわけではありません。パスに対してPUTを使用してどのURIを作成できるかに関するルールを作成でき、1つの有効なルールが「なし」であることは明らかです。そのために機能する可能性のあるいくつかのエラーコードは 400または422 です。上記のシナリオでは、403または404も意味があるかもしれないという主張をしました。個人的には、ここでは404を避け、「不正な入力」応答を使用して、PUTでのリソースの作成を許可していないことを明確にします。

[〜#〜]投稿[〜#〜]

POSTについても少し混乱があります。これはINSERTの概念と多少整合していますが、多くの人が見逃していると思う側面が1つあります。POSTリクエストのパスが、作成されるリソースを参照していないということです。親リソースのパスです。それはあなたがPOST

https://domain.com/{root}/{parent}

あなたは新しいリソースを作成することを求めています

https://domain.com/{root}/{parent}/{child}

識別子childはサーバーによって作成されます(クライアントにリクエストのコンテンツでそれを指定させることができないということは何もありません)。

したがって、質問のコンテキストでは、子が存在しないときに404を返すことは意味がありません。サーバーに子を作成するように要求していて、子をURIの一部にしてはならないからです。ただし、親リソースが存在しない場合、URIが存在しないリソースの子を作成するように要求するため、その場合は404を返すことは完全に理にかなっています。

結論として、404PUTおよびPOSTを一緒に使用しないことをお勧めします。ここでは子エンティティが不足していることを示しています。違う。 404を使用して、親パスが存在しないか、クライアントからアクセスできないことを示すことは意味があります。

3
JimmyJames

エキスパートの間で、データベースでAPIが探しているオブジェクトが見つからなかったことを示すために404を使用することに対して大きな合意があると言っても安心です。

主な問題は、ウェブサーバーまたはクライアントの設定が間違っている場合や、ドメインを誤って入力した場合にも404が表示されることです。

2つ目は、リソースが見つからない場合に例外をスローしたくないことがよくありますが、htmlライブラリは404コードの受信時に例外をスローすることがよくあります。

ただし、この目的で404を使用する場合、「存在しないリソースに対する更新の試み」に対しても、実装は十分に簡単です。

  • 取引を開始する
  • リソースの存在を確認する
  • 存在しない場合は、404を返し、トランザクションをロールバックします。
  • 存在する場合は、更新を続行してトランザクションをコミットします

おそらくより最適な「SQLを実行し、影響を受ける行数をチェックする」こともありますが、結果はより解釈しやすくなります。

404の代替(この部分は最初の文の説明が必要な人のみを対象としています)

基本的には、コードの設計に依存します。呼び出したメソッドが成功したかどうかをユーザーに確認させないようにします。これにより、明確でシンプルなコードを記述できます。

そう。回復できない場合の例外ですが、より重要なのは、例外をスローしないように設計されたメソッドです。

したがって、存在しない可能性のあるオブジェクトをロードしようとしている場合は、「存在しない」が例外的な状況ではなく、呼び出しの有効な結果であることを認識するメソッドを使用してください。

オブジェクトを更新しようとしている場合は、オブジェクトを開いている間に削除された場合のシステムの処理方法を考えてください。おそらく、まだ存在していないオブジェクトを作成することも、一致が一致しないセットを更新することもできます。

コードでは、get関数はnullを返し、更新は影響を受けた行数を返す場合があります。これらは、エラーコードではなく「null」または0として表すことができます。

5
Ewan