/note/tech

バリデーションはドメインオブジェクトとAPIスキーマ定義のどっちに書くべきか

要約:

■ 1. バリデーション定義の重複問題

  • バックエンドサーバのバリデーション定義が、ドメインオブジェクトとAPIスキーマ定義の両方で重複して定義される問題がある
  • 重複を避けるため片方に集約したいが、それぞれの選択肢に課題が生じる

■ 2. 実装パターン

  • ドメインオブジェクトに全部実装するパターン:
    • リポジトリパターンによってデータ登録・更新・削除が保証されるため、いつでも・どこでもバリデーションが適用可能
    • バッチ処理でもドメインオブジェクトを生成することでバリデーションが機能する
    • コードで記述するためプログラマブルなバリデーションが可能で、複雑な条件分岐にも対応できる
  • APIスキーマ定義に全部実装するパターン:
    • APIが期待する入力値の制約がスキーマ定義から一目で把握できる
    • マイクロサービス環境やAIによるAPI実装時の利便性が高い
    • 課題:
    • 複雑な条件分岐(有料会員のみのデータ登録制限など)は実装できない場合があり、結局ドメインオブジェクトにもバリデーションの実装が必要になる可能性がある
    • API経由の入力にしかバリデーションが効かないため、バッチ処理での直接DB登録にはバリデーションが機能しない
    • バリデーションエラーメッセージの柔軟な定義に制限がある場合がある(CEL式によるカスタムルールで日本語メッセージ等の対応は可能だが、手間がかかる)
  • 両方に定義するパターン:
    • 2重管理となりメンテナンスコストが高く、ルール変更時に両方の修正が必要
    • 亜種として「APIスキーマ定義のコメントにバリデーション定義を記述するだけ(実際にはバリデーションしない)」パターンも存在するが、機械的な検証ができないため複雑さが増す可能性がある

■ 3. 推奨パターンと考え方

  • APIスキーマ定義によるバリデーションを推奨する(APIスキーマ定義で実現できないバリデーションはドメインオブジェクトに実装する)
  • 「API経由の入力にしかバリデーションが効かない」問題への対応方針:
    • 入力をAPI経由のみに制限する
    • バッチ処理でのDB登録もAPIを経由し、直接DBに登録しない
    • バッチ処理の要件にマッチしない場合は専用エンドポイントを作成・改修する
  • APIに入力を集約することで得られる追加メリット:
    • バックエンドサーバの正常な挙動の保証
    • Rate Limitの適用
    • エンドポイントの認証・認可
    • ログ(監査ログ、アクセスログ、エラーログ)
    • アラート・モニタリング
  • データの入り口を一箇所に絞ることで可用性や信頼性が向上し、大規模サービスほどトラブル防止の恩恵が大きい
  • Amazonの「ベゾスの掟」もこの考え方と同様の方針であり、大規模開発組織やマイクロサービスの安全なスケールに寄与する
  • この推奨は、規模が大きくトラフィックが多い、開発組織が大きい、マイクロサービスを採用しているサービスを前提とした場合に特に有効