概要
購入作成 API (POST /purchase) で残高不足が 500 Internal Server Error で返る。残高不足はユーザー起因の正常な業務結果であり、サーバー障害ではないため 400 Bad Request で返すべき。
これは #9 (fix/item-id-validation-400) のクライアント起因エラーを 400 に寄せる方針と同じカテゴリの問題(同 PR のスコープ外として切り出し)。
現状の挙動
app/domain/service/purchase/can_purchase.go の CanPurchase は残高不足時に素の errors.New("insufficient balance") を返す
app/usecase/purchase/create_purchase.go:75 でそのエラーがそのまま伝播
app/ui/api/purchase/purchase.go:55-62 のハンドラで ErrItemNotFound 以外は全て else 分岐に落ち、500 になる
何が問題か
- フロントが「残高不足(ユーザー起因)」と「本当のサーバーエラー」を区別できない
- 500 はリトライや障害アラートを誘発する(残高不足はリトライしても無意味)
- OpenAPI の購入 POST には既に
400 が定義済み
提案する修正
既存の ErrItemNotFound(create_purchase.go:13)と同じ sentinel error パターンに揃える:
usecase/purchase に ErrInsufficientBalance sentinel を追加
- usecase 側で
CanPurchase の残高不足エラーを ErrInsufficientBalance でラップ(または CanPurchase 自体が sentinel を返す)
- ハンドラで
errors.Is(err, purchase.ErrInsufficientBalance) → 400 にマッピング
参考・優先度低(別issue候補)
入力検証エラー(NewPurchaseItem の itemID/quantity <= 0 等のドメイン検証失敗)も同様に 500 になる。ただしこれは RegisterUser(ドメイン検証 → 500)と同じ既存慣習で、上記 PR の変更が壊したものではない。「全体でドメイン検証エラーを 400 に統一するか」という設計判断の話なので、本issueとは分けて検討する。
関連ファイル
app/domain/service/purchase/can_purchase.go
app/usecase/purchase/create_purchase.go
app/ui/api/purchase/purchase.go
docs/openapi.yaml
概要
購入作成 API (
POST /purchase) で残高不足が500 Internal Server Errorで返る。残高不足はユーザー起因の正常な業務結果であり、サーバー障害ではないため400 Bad Requestで返すべき。これは #9 (fix/item-id-validation-400) のクライアント起因エラーを 400 に寄せる方針と同じカテゴリの問題(同 PR のスコープ外として切り出し)。
現状の挙動
app/domain/service/purchase/can_purchase.goのCanPurchaseは残高不足時に素のerrors.New("insufficient balance")を返すapp/usecase/purchase/create_purchase.go:75でそのエラーがそのまま伝播app/ui/api/purchase/purchase.go:55-62のハンドラでErrItemNotFound以外は全てelse分岐に落ち、500になる何が問題か
400が定義済み提案する修正
既存の
ErrItemNotFound(create_purchase.go:13)と同じ sentinel error パターンに揃える:usecase/purchaseにErrInsufficientBalancesentinel を追加CanPurchaseの残高不足エラーをErrInsufficientBalanceでラップ(またはCanPurchase自体が sentinel を返す)errors.Is(err, purchase.ErrInsufficientBalance)→400にマッピング参考・優先度低(別issue候補)
入力検証エラー(
NewPurchaseItemのitemID/quantity <= 0等のドメイン検証失敗)も同様に500になる。ただしこれはRegisterUser(ドメイン検証 → 500)と同じ既存慣習で、上記 PR の変更が壊したものではない。「全体でドメイン検証エラーを 400 に統一するか」という設計判断の話なので、本issueとは分けて検討する。関連ファイル
app/domain/service/purchase/can_purchase.goapp/usecase/purchase/create_purchase.goapp/ui/api/purchase/purchase.godocs/openapi.yaml