仕組み
エラー契約とは、失敗時のステータスコード、レスポンス形式、エラー識別子などの取り決めです。
ステータスが適切なら、クライアントは「入力を直す」「データを読み直す」「時間を置く」などを区別できます。
400・422・409の違い
| ステータス | 意味の中心 | APIでの例 |
|---|---|---|
400 Bad Request |
クライアント側の要求に問題がある | JSON構文が壊れている |
422 Unprocessable Content |
内容形式と構文は理解できるが、指示を処理できない | 終了日が開始日より前 |
409 Conflict |
対象リソースの現在の状態と競合している | 発送済みの注文をキャンセルしようとした |
500 Internal Server Error |
サーバー側で予期しない問題が起きた | 未処理の例外で処理が中断した |
この区別はHTTP仕様に基づきます。ただし、400は構文エラーだけに限定されたコードではありません。 バリデーションエラーを400に統一するAPIもあり、422との使い分けには設計上の選択があります。HTTP仕様:ステータスコード
409と412も区別する
「データが古い」という競合でも、HTTPの If-Match 条件が満たされなかった場合は、通常 412 Precondition Failed を使います。
PUT /articles/123
If-Match: "revision-7"
その記事がすでに別の人によって更新されていれば、上書きを拒否できます。
本文も機械的に扱える形式にする
エラーメッセージの文字列だけを見て分岐すると、文言変更や翻訳で処理が壊れます。
RFC 9457のProblem Detailsを使うなら、たとえば次の形式にできます。
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/invalid-date-range",
"title": "日付の範囲が不正です",
"status": 422,
"detail": "終了日は開始日以降にしてください。",
"instance": "/requests/req-123",
"errors": [
{
"field": "endDate",
"code": "BEFORE_START_DATE"
}
]
}
type などは標準の項目です。この例の errors は、フィールド単位の問題を表す独自拡張です。RFC 9457:Problem Details
クライアントは、安定した type やエラーコードで分岐し、説明文は表示に使います。
すべて500にすると何が困るか
入力ミスまで障害として監視され、利用者にも修正方法が伝わりません。また、クライアントが自動再試行すると、直らない要求を繰り返す可能性があります。
逆に、500だから処理が一切実行されていないとも限りません。書き込みの再試行には、1番の冪等性が必要です。
設計上の要点
エラーは、失敗の報告と、次の行動を決めるためのAPIの一部です。