Skip to content

ドメイン検証エラー(クライアント起因)の500を400に統一する #14

@ayuayuyu

Description

@ayuayuyu

概要

ドメイン層の検証エラー(入力起因 = クライアント起因)が一部のハンドラで 500 Internal Server Error に落ちている。エラーの責務に応じて 400 Bad Request を返すよう、全エンドポイントで一貫した方針に統一したい。

これは #13(残高不足 → 400)と同根の「クライアント起因エラーを 400 に寄せる」設計判断の話。#13 は残高不足に限定したスコープのため、こちらで横断的な方針を扱う。

現状の不整合

ドメイン検証エラーの扱いがエンドポイントごとにバラバラ:

箇所 ドメイン検証エラーの扱い
user.go GET (ErrInvalidUserID) 400(sentinel + errors.Is でマッピング済み)✅
user.go RegisterUser ErrUserAlreadyExists のみ 409、その他ドメイン検証は 500
purchase.go CreatePurchase NewPurchaseItem(itemID/quantity <= 0)・NewPurchase 等の検証失敗が 500

user.goErrInvalidUserID だけが正しく 400 に寄っており、他は素の errors.New(...) を返すため sentinel 判定ができず 500 に落ちる。

何が問題か

  • 同じ「不正入力」でもエンドポイントによって 400 だったり 500 だったりして、フロントの扱いが一貫しない
  • クライアント起因のエラーで 500 が返ると、リトライ・障害アラートを誘発する
  • 既に ErrInvalidUserID という良いお手本があるのに、他が踏襲できていない

提案する方針

ErrInvalidUserID のパターンを横展開する:

  1. ドメイン検証エラーを sentinel error として定義(または検証エラーをまとめる ErrInvalidInput 的なマーカーを導入)
  2. usecase 層で sentinel をラップして伝播
  3. ハンドラで errors.Is(...)400 にマッピング

NewPurchaseItem / Set* など多数の検証関数があるため、個別 sentinel 乱立を避けて「ドメイン検証エラー」を表す共通マーカー error を1つ用意する案も検討したい(要相談)。

関連ファイル

  • app/domain/object/purchase/purchase.goNewPurchaseItem, Set* 検証群)
  • app/domain/object/user/SetUserID 等)
  • app/usecase/purchase/create_purchase.go
  • app/ui/api/purchase/purchase.go
  • app/ui/api/user/user.go

備考

これは既存慣習であり、特定 PR が壊したものではない。横断的な設計判断を要するため、実装前に共通マーカー方式か個別 sentinel 方式かを決めたい。

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions