APIエラーコードとベストプラクティス
1)エラーを標準化する理由
顧客の予測可能性:単一のフォーマットとレトラの動作。
デバッグアクセラレーション:'trace_id'/'request_id'、安定した'error_code'。
セキュリティ:SQL/stack traces/configsは漏れません。
オブザビリティ:エラータクソノミ(検証、クォータ、タイムアウトなど)に関するレポート。
2)基本原則
1.すべての4xx/5xxの単一の応答フォーマット(および部分的なエラーがある2xxの場合-別のスキーム)。
2.明確なHTTPセマンティクス:正しいステータスが最も重要です。
3.2つのレベルのコード:transport ('status')とdomain stable 'error_code'。
4.RetriableとNon-retriable:明示的に指定し、バックオフについてヒントを与えます。
5.デフォルトのセキュリティ:詳細-権利を持つクライアントのみ;内部の痕跡なし。
6.ローカライズ:マシンコードは安定したまま、テキスト-翻訳します。
3)単一のエラー形式(RFC 7807に基づく)
推奨JSON(拡張'application/problem+json'):json
{
"type": "https://api. example. com/errors/validation_failed",
"title": "Validation failed",
"status": 422,
"error_code": "VAL_001",
"detail": "Field 'email' must be a valid address",
"instance": "req_01HZY...93",
"trace_id": "a1b2c3d4e5f6",
"retriable": false,
"errors": [
{"field": "email", "code": "email_invalid", "message": "Invalid email"}
],
"hint": "Fix payload and retry",
"meta": {"docs": "https://docs. example. com/errors#VAL_001"}
}
必須:'type'、 'title'、 'status'、 'error_code'、 'trace_id'。
オプション:'errors[]'(フィールド別)、'retriable'、 'hint'、 'meta'。
- 'Content-Type: application/problem+json'
- 'X-Request-ID'/'Traceparent' (W3C)
- (429/503の場合)'Retry-After'(秒または日付)
4) HTTPステータスのセマンティクス(「古典」と練習のマージ)
2xx(微妙な成功)
200 OKは一般的な成功です。
201作成-ロケーション。
202 Accepted-キュー内で非同期に('status_url'を与える)。
207マルチステータス-部分的な成功(可能であれば回避)。
4xx(クライアントエラー)
400 Bad Request-構文/フォーマットですが、フィールド検証ではありません(好ましくは422)。
401無許可-いいえ/無効なトークン。「WWW認証」しましょう。
403禁じられた-トークンは有効ですが、十分な権利(RBAC/ABAC/limits)がありません。
404 Not Found-リソース/エンドポイントがありません。
409競合-最適なロック、idempotency。
410 Gone-エンドポイントが永久に削除されました。
412必須条件に失敗しました-ETag/If-Matchに失敗しました。
415サポートされていないメディアタイプ-無効な'Content-Type'。
422処理不可能なエンティティ-ビジネスルールの検証。
429リクエストが多すぎる-クォータ/スピードを超えました(第7条を参照)。
5xx(サーバーエラー)
500内部サーバーエラー-突然のエラー。詳細を開示することはできません。
502 Bad Gateway-アップストリームエラー。
503サービスが利用できません-劣化/過負荷、'Retry-After'を与えます。
504ゲートウェイタイムアウト-バックエンドのタイムアウト。
5)ドメインタクソノミ'error_code'
以下の範囲をお勧めします:- 'AUTH_'-認証/承認。
- 'VAL_'-入力データの検証。
- 'RATELIMIT_'-クォータと速度。
- 'IDEMP_'-idempotence/duplicates。
- 'CONFLICT_'-バージョン/ステータス。
- 'DEP_'-依存関係(PSP/DNS/SMTP)。
- 'PAY_'-決済ドメインのビジネスエラー。
- 'SEC_'-セキュリティ(署名、HMAC、 mTLS)。
- 'INT_'-内部が突然になりました。
- 時間をかけた安定性(バックコンパット)。
- エラーディレクトリ(docs+machine-readable JSON)の説明と例。
6)検索可能なvs検索不可
フィールド:- 'retriable: true' false'
- 'true'の場合-必ずしも'Retry-After'(秒単位)または「exponential back-off (1-2 sから始まり、最大30-60 s)」。
通常は'502/503/504'、 '500'、'429'(ウィンドウの後)です。
検索不可:'400/401/403/404/ 409/410/415/422'。
7)レートリミット&クォータエラー(429)
ボディ:json
{
"type": "https://api. example. com/errors/rate_limited",
"title": "Rate limit exceeded",
"status": 429,
"error_code": "RATELIMIT_RPS",
"detail": "Too many requests",
"retriable": true
}
タイトル:
- 'Retry-After: 12'
- 'X-RateLimit-Limit'、 'X-RateLimit-Remaining'、 'X-RateLimit-Reset'
- 「X-Quota-Limit」「、X-Quota-Remaining」「、X-Quota-Reset」
8)アイデンポテンスと競合
書き込みリクエスト-'Idempotency-Key' (24-72時間以内に一意)。
競合の再試行→409 'error_code: "IDEMP_REPLAY"'と競合します。
ETag→412 Preconditionのリソースバージョンの競合に失敗しました。
レスポンスでは、セキュアな再リクエストのために'resource_id'/'status_url'を添付します。
9)検証と422
フィールドごとにエラーのリストを返します:json
{
"status": 422,
"error_code": "VAL_001",
"errors": [
{"field":"email","code":"email_invalid","message":"Invalid email"},
{"field":"age","code":"min","message":"Must be >= 18"}
]
}
ルール:
- ビジネス検証のために好ましい400〜422で同じことを複製しないでください。
- メッセージは人間が読めるものです。'code'は機械読み取り可能です。
10)エラーセキュリティ
Never:スタックトレース、SQL、ファイルパス、プライベートホスト名。
PIIを編集します。GDPR/DSARに注目してください。
署名/HMACの場合、プロンプト「check ± time 5 min」で'SEC_SIGNATURE_MISMATCH' (403)と'SEC_TIMESTAMP_SKEW' (401/403)を区別します。
11)相関および観察可能性
常に'trace_id'/'X-Request-ID'を追加し、ログ/トラックをスクロールします。
'error_code'と'status'→ダッシュボード「top errors'、」 new vs known'でエラーを集計します。
アラート:5xx/422/429スパイク、p95レイテンシ、エラーの共有。
12) gRPC/GraphQL/Webhooks-マッピング
gRPC ↔ HTTP
GraphQL
200を転送しますが、'errors[]'の内部-'extensionsを追加します。'trace_id'というコードです。
「致命的な」(認証/クォータ)-実際のHTTP 401/403/429の方が良いです。
Webhooks
成功した受信者は2xxのみを考慮してください。
指数関数的バックオフ、'X-Webhook-ID'、 'X-Signature'を持つレトライ。
受信者から410-リトレイを停止(エンドポイントが削除されました)。
13)エラーバージョニング
'type'/'error_code'-stable;new-追加のみ。
ボディスキーマを変更する場合は、APIまたは'problem+json;のマイナーバージョンを上げます。v=2'。
ドキュメント:コードテーブル+例;changelogエラー。
14)ドキュメント(OpenAPIフラグメント)
グローバルな対応
yaml components:
responses:
Problem:
description: Problem Details content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
schemas:
Problem:
type: object required: [type, title, status, error_code, trace_id]
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
error_code: { type: string }
detail: { type: string }
instance: { type: string }
trace_id: { type: string }
retriable: { type: boolean }
errors:
type: array items:
type: object properties:
field: { type: string }
code: { type: string }
message: { type: string }
エンドポイントの例
yaml paths:
/v1/users:
post:
responses:
'201': { description: Created }
'401': { $ref: '#/components/responses/Problem' }
'422': { $ref: '#/components/responses/Problem' }
'429': { $ref: '#/components/responses/Problem' }
'500': { $ref: '#/components/responses/Problem' }
15)テストおよび質
テスト契約:'application/problem+json'、必須フィールドにマッチします。
否定的なテスト:すべての枝401/403/404/ 409/422/429/500。
カオス/レイテンシ:5xx/ 503/504/429 ('Retry-After')のリトレイをチェックします。
セキュリティテスト:内部メッセージなし、正しいPIIマスク。
Backward-compat:古い顧客は新しいフィールドを理解している(add、 don 't break)。
16)実装チェックリスト
- シングル'problem+json'+stable 'error_code'。
- HTTP/gRPC/GraphQLセマンティクスを修正します。
- Retriable/non-retriable+'Retry-After'/バックオフの推奨事項。
- レートリミットヘッダーと429の動作。
- Idempotency ('Idempotency-Key'、 409/412)。
- セキュリティ:いいえスタックトレース/シークレット、PII版。
- 'trace_id'/'X-Request-ID'のすべてのエラー。
- エラーカタログのドキュメントと例。
- エラータクソノミによるモニタリング。
- 否定的なシナリオのAutotests。
17) ミニFAQ
400は422とどう違うのですか?
400-壊れたリクエスト(構文/コンテンツタイプ)。422-構文で有効ですが、ビジネスルールは渡されませんでした。
401はいつ、403はいつですか?
401-いいえ/間違ったトークン。403-トークンがあり、十分な権利がありません。
「再試行後」は必要ですか?
429/503のために、はい;残りのために、検索可能-明示的な勧告を与えることをお勧めします。
合計
適切に設計されたバグはコントラクトです:正しいHTTPステータス、単一の'問題+json'、安定した'error_code'、明示的なリトレイヒント、強力なセキュリティ。フォーマットを標準化し、分類を文書化し、テレメトリーとテストを追加し、APIは予測可能で安全でインテグレータに優しいものになります。