web-dev-qa-db-ja.com

「結果なし」はRESTful応答のエラーである必要がありますか?

例を説明します。
ベーキングショップ用のAPIの作成を開始します。 APIを使用すると、api.examplebakery.com/search?q=.....を使用して、自家製のミントチョコレートチップクッキーなどのベーキング製品をカタログで検索できます。

誰かがこれを使用してpineapple-banana flavoured cookiesという名前の製品を検索すると、明らかに結果が見つかりません。

これはエラーとして返されますか?検索は失敗せず、APIが検索し、Cookieが見つからなかったと結論付けました。 APIが実際に見つかったため、APIは404を返すべきではありません。

54
Berry M.

結果がある場合、出力は(コメントに基づくJSON)リストです。結果のないクエリの場合、出力はまったく同じになります。リストの項目は0です。

したがって、応答が通常これである場合:

{
    "results": [
        {
            "name": "Pancakes",
            ....
        },
        {
            "name": "French Fries",
            ....
        }
    ]
}

次に、結果が0のクエリの場合、次のようになります。

{
    "results": []
}

結果の「ページ」の数に関するメタデータ、それらの「ページ」へのリンクなども含める場合、1つの「ページ」があるとお勧めします。

HTTPステータスは、結果がある場合と同じである必要があります-200 OK

204 No Contentもオプションのように見えるかもしれませんが、実際には「コンテンツ」を返すからではありません-空のリスト。空のリストが「コンテンツ」としてカウントされないと思われる場合は、スペルの提案を提供するように応答を修正するとどうなりますか?応答の中心は空のリストのままですが、さらに多くの「コンテンツ」があります。

HTTPステータスコードの詳細については、 jpmc26に回答があります 読む価値があります。

125
Jory Geerts

HTTPコードを決定するときはいつでも、常にこの質問をする必要があります。

任意のクライアントが応答で何ができる/する/すべきでしょうか?

  1. クライアントはalways応答を失敗として処理する必要がありますか?次に、問題がクライアントの入力かサーバーのプロセスかに応じて、4xxまたは5xxが必要になります。
  2. クライアントは代わりにどこかでリクエストを行う必要がありますか?その後、3xxはあなたのためです。
  3. サーバーは、クライアントが要求した(成功した)ことを行いましたか?それは2xxです。

応答コードを最初に含める範囲を常に決定します。そうすることで、オプションとしての多くの応答コードがすばやく排除され、(おそらくより重要なことですが)コードのセマンティクスをたどることがはるかに簡単になります。コードの各カテゴリが何を表すかについては、 HTTPコードのドキュメント の最初のセクションを参照してください。

この場合、クライアントは、有効な既存のエンドポイントからのフィルターを指定した結果のリストを要求し、それにアクセスする権限を持っています。サーバーは要求を処理し、返すべき適切なデータ(アイテムなし)を決定できたため、要求は成功しました。彼らが与えたフィルターがフィルターで除外されただけですall結果。これが一部のクライアントにとって予期される結果である可能性があるため、これがクライアントが望んでいたものかどうかを判断するのはサーバーの責任ではありません。それがクライアントコードにとってなんらかの問題である場合は、クライアントが適切に判断、確認、および処理する責任があります。これは明らかに2xxです。

ここで問題は、「どちらの2xxですか」です。これは、サーバーの応答方法によって異なります。

  • 他のいくつかの回答 説明のような空のリストの表現を送り返しますか?その場合、200が必要です。200は、サーバーで問題が発生しておらず、クライアントが消費する結果を示していることを意味します。これは、結果があるかどうかに関係なく応答を解析し、空のリストを自分で処理する方法を理解できる、コンシューマーにとって最も便利な応答方法です。
  • ここで204は意味的に間違っているわけではありませんが、メッセージ本文はありませんで応答する必要があります。つまり、すべてのクライアントコードは、さまざまなHTTPコードを(または少なくともメッセージ本文がないことを)明示的にチェックし、個別に処理する必要があります。それは不便であり、振る舞いの悪いクライアントにつながる可能性が高くなります。

その他はまったく適用されません。

  • 201は問題外です。永続リソースを作成しておらず、作成したリソースに場所を返していません。
  • 202は問題外です。リクエストが完了しました。バックグラウンドで処理されていません。
  • 203は、権限のあるサーバーとクライアントの間で応答が変更されたことを意味します。 RESTfulインターフェースis権限のあるサーバーなので、これはここでは適用されません。
  • 205は意味がありません。クライアントが何かをクリアまたはリフレッシュする必要はありません。
  • 206は、複数の応答で大量のリソースを返すように設計されているようです。また、クライアントaskのコンテンツの一部ヘッダー内も必要です(そのため、クエリ文字列によるページ付けは対象外です)。ここでは適用されません。

したがって、200または204のいずれかである必要があり、200はより単純でより堅牢なクライアントコードにつながる可能性が高くなります(特に、空のリストを含む一貫した応答構造を使用する場合)。

39
jpmc26

いいえ。404を使用して「クエリは処理されましたが、一致するものはなかった」ことを示すのは、次の理由によりひどいです。

  • 例外処理に基づく条件付きフロー(つまり、非例外的な結果を強制して、クライアントで例外を作成して処理します。これは、パフォーマンスが低く、扱いにくい場合があります)

  • 「実際の」ページのあいまいさが見つかりません。エンドポイントを入力したときにエラーが発生しました

覚えておくべきことは、メッセージを逆シリアル化するクライアントが常に存在し、そのクライアントが返すものは重要であることです。シリアライゼーションではありません。

クライアントがnullを返す必要がある場合は、nullのシリアル化を使用します。クライアントが空の配列を返す場合は[]を使用し、クライアントがエラーをスローする場合は500を使用してエラーメッセージを渡します

16
Ewan

@Ewanの非常に良い答えを超えて:

クエリが結果のセットを返す種類である場合、空のセットは論理的には1つまたは複数のセットと同じくらい適切です。一般的に、@ Ewanが述べている理由から、空のセットをエラーに変更することは良いことよりも害があり、それは単に不要です。

クエリが検索して特定のシングルトン(IDによる完全一致など、見つかると予想される)を返す種類の場合、論理的に適切な可能な応答は見つかりません。

9
Erik Eidt

データが返されない場合、コードは特別なアクションを実行する必要があると想定していますが、そうではない場合があります。コードは単に製品数を探しているか、結果をリストまたは任意の数の項目に追加している可能性があります。実際にエラーがある場合にのみ、ユーザーに「エラー」を与える必要があります。

5
John Smith

APIを使用する場合、クライアントとして「エラー」ケースとは異なる「成功」ケースを処理する必要があります。そこに選択肢はありません。したがって、クライアントwantsが異なる扱いをする状況ではエラーを返し、クライアントwantsが同じ扱いをする状況では成功を返す必要があります。

理論的には0、1、200などの任意の数の結果を返すクエリを実行する場合、APIがすべての結果の完全なリストを提供するときはいつでも、「成功」を返す必要があります。そして、おそらく多くの結果がある場合は、過度のサイズを回避するために結果の部分的なリストを返しましたが、他の結果を得る方法については合意された方法があります。それは、クライアントとして、結果がゼロの場合のように、より多くの結果の場合と同様に処理したい場合があるためです。私はそれを違った扱いをするかもしれませんが、私は強制されたくありません。

値を検索する場合は異なります。ちょうど1つの結果、つまり私が探している値を期待しています。そして、私がやりたいことを有意義な方法で継続するには、その1つの結果が必要です。ここでは、値が存在しない場合にステータス404を返す方がはるかに受け入れられます。なぜなら、私はとにかくそのケースを異なる方法で処理する必要があるからです。

要約:クライアントが0から大きな数までの任意の数の結果を予期している場合、すべての結果が配信されれば、その数がゼロであっても「成功」を返します。クライアントが正確に1つの結果を期待している場合、結果が見つかった場合は成功を返し、結果が見つからなかった場合はエラーを返します。

0
gnasher729