WebAPIの戻り値レビュー用メモ。HTTPステータスの妥当性を考える

コントローラーのコードレビューやコードリーディングで、処理の最後が「とりあえず return Ok(...)」「失敗したら全部 BadRequest()」になっていると、「本当にこのステータスコードで合っているのか?」と手が止まります。

AIが書いたAPIの戻り値を見る時も同じです。「この処理はどこまで終わったのか」「呼び出し側はこれを見て次に何をするのか」を毎回確かめるためのメモです。チームの規約やAPIの契約がある時は、そちらと照らして確認します。

コードレビューで確認する順番

コントローラーの戻り値を見たら、私は次の順で処理を追います。

  1. HTTPメソッドと処理の目的: 読み取り、作成、更新、削除、非同期ジョブの受付のどれか。
  2. 実際に処理が完了した状態: リソースを作ったのか、処理を受け付けただけなのか、失敗したのか。
  3. 戻す本文とヘッダー: 応答本文はあるか。作成したリソースの場所や、再試行に必要な情報を返しているか。
  4. クライアントに伝わる意味: 呼び出し側がこのコードを見て、成功・入力修正・認証・再試行などを正しく判断できるか。
  5. コード上の宣言との一致: 戻り値の型、属性、OpenAPI記述、実際の応答が同じ契約を示しているか。

ASP.NET Coreのコントローラーでは、たとえば ActionResult<T> で本文の型と複数の ActionResult を表せます。[ProducesResponseType]などの宣言があっても、実際の分岐で返すステータスと本文が一致しているかは別に確認します。Microsoftの公式ドキュメントも、戻り値の型や複数の応答を示す方法を案内しています。

受付だけ済んだ処理なら、202を考える

例えば、エクスポートの依頼をジョブのキューに登録し、ファイルの作成はこれから、という処理を考えます。

応答の項目 値
HTTPステータス 202 Accepted
Locationヘッダー /export-jobs/123
Content-Typeヘッダー application/json

応答本文は次のJSONです。

{"id":123,"status":"pending"}

この時点で終わっているのは「ジョブの受付」だけで、ファイル作成はこれからです(以下は実案件の応答ではなく、読み方を整理するための例です)。ここで 200 OK を返してしまうと、呼び出し側は「もうファイルができた」と受け取ってしまいます。受付だけで返すなら 202 Accepted にして、Location のURLや本文の status で進行状況を確認できるかをチェックします。

処理の成功・失敗から2xx、4xx、5xxの候補へ進み、本文やヘッダー、API契約との一致を確認する判断図
代表的な分岐を俯瞰するための図です。コードだけで責任の所在を決めず、処理結果とAPI契約に照らして選びます。

まず成功応答の200系を選ぶ

200 OKはよく使いますが、成功応答がすべて200とは限りません。処理が何をしたか、応答本文や次に参照できるリソースがあるかで見分けます。

コード 意味 コントローラーを読む時に確かめること
200 OK リクエストが成功した 返している本文が、操作の結果や対象リソースを表しているか
201 Created 新しいリソースを作成した 何を作成したか。作成したリソースを Location などで示しているか
202 Accepted 処理を受け付けたが、まだ完了していない 非同期処理など、受け付け後に結果を確認する方法があるか。処理完了を誤って示していないか
204 No Content リクエストは成功したが、本文を返さない 呼び出し側が本文を必要としていないか。空の本文とステータスが合っているか
206 Partial Content 要求された範囲の一部を返した Range要求に応じた応答など、部分データを返す文脈があるか

典型例として、作成したリソースを返すなら 201、処理を受け付けただけなら 202、本文を返さない更新や削除なら 204 が候補になります。どのエンドポイントもこの形に固定するのではなく、APIの契約と実際に返す内容を見ます。203や205など、ほかの成功コードも仕様にあります。コードを見た時は、その応答の意味がAPIの契約と合っているかを確認します。

仕様(RFC 9110)を読むと、200 は条件によって「推測でキャッシュ可能」と書かれています。ただ、200 を返しただけで無条件にブラウザーやプロキシへ保存・再利用されるわけではなく、実際にはGETなどのメソッドや Cache-Control ヘッダーの指定に左右されます。キャッシュの扱いが関わるAPIでは、ステータスコードだけでなく応答ヘッダーも合わせて確認します。

400系と500系は、リクエストと処理結果のどちらを示すか

ざっくり見る時は、クライアントのリクエストに起因する応答か、サーバーが有効なリクエストを完了できなかった応答かを分けます。コードの番号だけで「どちらが悪いか」を決めつけるのではなく、ログや契約と照らして切り分けます。

系統 大まかな意味 見るポイント
400系 クライアントからのリクエストに関する問題 入力、認証・認可、対象リソースの現在状態、前提条件を確認する
500系 サーバーが有効なリクエストを完了できなかった 例外、依存サービス、ゲートウェイ、過負荷など、サーバー側の状態を確認する

よく読む400系

コード 意味 コントローラーを読む時に確かめること
400 Bad Request リクエストの形式や内容に問題があり、処理できない 構文、必須項目、値の形式のどこで拒否しているか
401 Unauthorized 有効な認証がない 認証情報の有無・有効性と、必要な認証チャレンジが返るか。権限不足の403と混同していないか
403 Forbidden リクエストを理解したが実行を拒否する 認証状態だけでなく、操作を拒否する理由とAPIの認可方針が合うか
404 Not Found 対象リソースが見つからない、または存在を隠す ID・検索条件が正しいか。情報を隠す目的で一貫して使っているか
405 Method Not Allowed 対象リソースがそのHTTPメソッドを受け付けない ルート設定とメソッドが合うか。許可メソッドを示す Allow ヘッダーがあるか
409 Conflict 対象リソースの現在の状態と競合する 重複登録や状態遷移など、クライアントが競合を解消して再試行できる情報があるか
412 Precondition Failed リクエストで指定された前提条件が成立しない If-Match などの条件付きリクエストを正しく評価しているか
415 Unsupported Media Type リクエスト本文のメディア形式を処理できない Content-Type と、APIが受け付ける形式が一致しているか
422 Unprocessable Content 形式は理解できるが、内容の指示を処理できない 構文エラーの400と意味上の検証エラーをどう分けるか。API内で一貫しているか
429 Too Many Requests 一定時間内のリクエスト数が制限を超えた 制限条件と再試行の案内があるか。必要なら Retry-After を返しているか

よく読む500系

コード 意味 コントローラーを読む時に確かめること
500 Internal Server Error 予期しないサーバー側の状態で処理を完了できない 例外を適切に記録し、内部情報を応答へ漏らしていないか
501 Not Implemented サーバーが要求を処理する機能に対応していない 未対応の機能・メソッドを示す応答か。一時的な障害の503と混同していないか
502 Bad Gateway ゲートウェイやプロキシが上流から無効な応答を受け取った 実際に中継役の応答か。アプリ自身の処理失敗を502としていないか
503 Service Unavailable サーバーが一時的に処理できない メンテナンスや過負荷などの一時的な状態か。必要なら Retry-After を案内しているか
504 Gateway Timeout ゲートウェイやプロキシが上流から時間内に応答を得られない 上流応答のタイムアウトか。アプリ内部のタイムアウトを504としていないか

502・503・504は、リバースプロキシやゲートウェイが返すことも多いコードです。コントローラーの中で外部APIの失敗を捕まえた時に、アプリ側からそのまま 502 や 504 を返していいのか、それとも自分のサーバーの失敗として扱うのか。どの層が何の理由で返した応答なのかを確認します。

失敗の本文はHTTPステータスと一緒に読む

HTTPステータスを 200 OK のままにして、本文に { "status": "error" } を入れる形だと、呼び出し側はHTTP応答と独自の本文を両方解釈しなければなりません。監視やクライアントの共通エラー処理でも、失敗をHTTP上の成功と誤認しやすくなります。

エラーの詳細を共通化したい場合は、Problem Details(RFC 9457)を選択肢にできます。たとえば、HTTP応答そのものが 404 Not Found で、本文が application/problem+json のProblem Details形式である、という組み合わせです。本文にある status は補助情報なので、HTTP応答そのもののステータスコードも 404 Not Found などに揃えます。既存のエラー形式がプロジェクトで決まっているなら無理に置き換えず、共通の形式を新しく選ぶ時の選択肢にします。

次にコントローラーを読む時の自分用チェック

  • 200系のどれを返すかは、処理が実際に完了した状態と本文に合っているか。
  • リソースを作成した時、201と作成結果への参照を返しているか。
  • 202を返す時、非同期処理が未完了だとクライアントに伝わるか。
  • 204の時、呼び出し側が読む本文を返していないか。
  • 400系の選択が、入力・認証・権限・状態競合のどれを表すか。
  • 500系の選択が、サーバー・依存先・ゲートウェイの失敗に合っているか。
  • 本文、ヘッダー、戻り値の型、API仕様書の説明に矛盾がないか。

ステータスコードを見るときは、単なる「成功かエラーか」ではなく、「処理がどこまで終わり、呼び出し側が次にどう動けるか」を確かめます。「とりあえず200」「失敗だから400」で流さず、AIが書いたコードを読む時もこの順でチェックします。

確認した公式情報

2026年9月27日に確認。

コメント

タイトルとURLをコピーしました