エラー処理パターン
本番アプリケーション向けの一貫した堅牢なエラー処理パターン。
アクティベートするタイミング
- 新しいモジュールやサービスのエラー型や例外階層を設計する場合
- 信頼性の低い外部依存関係に対してリトライロジックやサーキットブレーカーを追加する場合
- APIエンドポイントでエラー処理の欠落をレビューする場合
- ユーザー向けエラーメッセージとフィードバックを実装する場合
- カスケード障害やサイレントなエラー飲み込みをデバッグする場合
コア原則
- 早く大きく失敗する — エラーが発生した境界で表面化させる。埋め込まない
- 文字列メッセージより型付きエラー — エラーは構造を持つファーストクラスの値
- ユーザーメッセージ ≠ 開発者メッセージ — ユーザーには親しみやすいテキストを表示し、詳細なコンテキストはサーバー側でログに記録する
- エラーをサイレントに飲み込まない — すべての
catchブロックは処理、再スロー、またはログのいずれかを行う必要がある - エラーはAPIコントラクトの一部 — クライアントが受け取る可能性があるすべてのエラーコードをドキュメント化する
TypeScript / JavaScript
型付きエラークラス
// ドメインのエラー階層を定義する
export class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500,
public readonly details?: unknown,
) {
super(message)
this.name = this.constructor.name
// トランスパイルされたES5 JavaScriptでプロトタイプチェーンを正しく維持する。
// 組み込みのErrorクラスを拡張する際に`instanceof`チェック
// (例: `error instanceof NotFoundError`)が正しく動作するために必要。
Object.setPrototypeOf(this, new.target.prototype)
}
}
export class NotFoundError extends AppError {
constructor(resource: string, id: string) {
super(`${…