Skip to content

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

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 方式かを決めたい。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions