コントローラーのコードレビューやコードリーディングで、処理の最後が「とりあえず return Ok(...)」「失敗したら全部 BadRequest()」になっていると、「本当にこのステータスコードで合っているのか?」と手が止まります。
AIが書いたAPIの戻り値を見る時も同じです。「この処理はどこまで終わったのか」「呼び出し側はこれを見て次に何をするのか」を毎回確かめるためのメモです。チームの規約やAPIの契約がある時は、そちらと照らして確認します。
コードレビューで確認する順番
コントローラーの戻り値を見たら、私は次の順で処理を追います。
- HTTPメソッドと処理の目的: 読み取り、作成、更新、削除、非同期ジョブの受付のどれか。
- 実際に処理が完了した状態: リソースを作ったのか、処理を受け付けただけなのか、失敗したのか。
- 戻す本文とヘッダー: 応答本文はあるか。作成したリソースの場所や、再試行に必要な情報を返しているか。
- クライアントに伝わる意味: 呼び出し側がこのコードを見て、成功・入力修正・認証・再試行などを正しく判断できるか。
- コード上の宣言との一致: 戻り値の型、属性、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 で進行状況を確認できるかをチェックします。
まず成功応答の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日に確認。
- RFC 9110: HTTP Semantics(HTTPステータスコードの意味)
- RFC 9111: HTTP Caching(キャッシュの仕組みと制御)
- RFC 6585: Additional HTTP Status Codes(429 Too Many Requests)
- RFC 9457: Problem Details for HTTP APIs
- Controller action return types in ASP.NET Core web API(Microsoft Learn)

コメント