🐨

Web API でバリデーションいい感じにやっておいてと言われたら

2022/08/25に公開

はじめに

  • Web APIでいい感じにバリデーションをやっておいてと言われたので[1]、何がいい感じなのか言語化してみました
  • 自分の考えがあっているかどうか気になったので書いてみました

いい感じのバリデーションとは?

  • いい感じを満たすには下記のバリデーションが必要なのかなと考えています
    1. アプリケーションにアクセスするユーザを特定する「認証」のバリデーション
    2. 特定したユーザが実行できる操作か確認する「認可」のバリデーション
    3. リクエストパラメータやリクエストボディが不正な値ではないかのバリデーション
      いるかなどのチェック
    4. ビジネスロジックのバリデーション
  • また、バリデーションの順番は下記の表の順番で行われるべきなのかと考えています
順序 バリデーションの内容 クラス HTTPのレスポンスのステータスコード
1 認証 @RestController[2][3] 401 Unauthorized
2 認可 @RestController[2:1][3:1] 403 Forbidden
3 パラメータのチェック @RestController[3:2] 400 Bad Request
4[4] パラメータのチェック @Service[3:3] 400 Bad Request
5 対象リソースの存在チェック[5] @Service 404 Not Found
5 対象リソースの操作をしてよいかのチェック[6] @Service 403 Forbidden
5 不正な値でDBを更新や削除しようとしていないかのチェック[7] @Service 403 Forbidden

おわりに

  • 書籍を読んでいるとどのようなアノテーションを使うとバリデーションができるといった使い方の話はよく見かけるのですが、どんな観点でどこでバリデーションすべきなのかの情報が多くないように見えたので、自分が考えている観点をまとめてみました(単純に検索ワードや自分の視野が狭いだけかもしれないですが...)
  • ビジネスロジックで行うバリデーションで問題があったときは、アプリ独自の例外をスローするのか、IllegalStatementExceptionをスローすべきなのか判断基準やベストプラクティスはあるのでしょうか?
  • DB側の仕組みで対象のリソースの操作をしてよいかのチェックができる方がより堅牢なのかと思います

参考

  • https://www.slideshare.net/koichiromatsuoka/postgresql-springaop
    • DB側でリソース操作を制御して、仕組みで実装ミスがあった時でも予防線が張れるのだなと勉強になりました
  • https://gihyo.jp/book/2016/978-4-7741-8217-9
    • 「いい感じ」と言われて、下記の言葉が考える起点になりました

    一般的にはバリデーションは「プレゼンテーション層における入力チェック」とほぼ同等の意味で捉えられてしまい、プレゼンテーション層で備えるべき機能だと思われることが多い。しかし本質的なバリデーションというのは、本来はビジネスロジックとして定義されるべきであり、...

  • https://little-hands.booth.pm/items/3363104
    • リクエストパラメータやリクエストボディからエンティティや値オブジェクを生成し、それを引数としてビジネスロジック層のクラスのメソッドを呼び出せば、プレゼンテーション層のバリデーションだけで最低限は良いのかなと思っています。プレゼンテーション層とビジネスロジック層のどちらでもバリデーションをしておけば、より堅牢になると思いますが、修正があった時に2ヶ所に修正を入れる必要が出てくるのかなと考えていて、どちらがより良いのか判断がついていません。
脚注
  1. 最近はチームリーダーのような業務もあり、メンバーに業務指示を出すために言語化する必要がありました。 ↩︎

  2. Spring Serurityが設定通りによしなに対処してくれる認識です。 ↩︎ ↩︎

  3. ざっくり@RestControllerはプレゼンテーション部分、@Serviceはビジネスロジック部分を実装するクラスの理解であっているかと思います。 ↩︎ ↩︎ ↩︎ ↩︎

  4. @RestControllerのクラスでリクエストパラメータやリクエストボディの値からアプリ独自のクラスのインスタンスを生成して、@Serviceのクラスのメソッドの引数に渡すこともあると思今ます。インスタンス生成時にバリデーションが行われるはずなので、場合によっては不要の認識です。 ↩︎

  5. 更新や削除しようとしているリソースがあるのかどうかのチェックを想定しています。 ↩︎

  6. ユーザAのリソースは自身しか参照できない仕様の時に、ユーザBがそのリソースを参照しようとしていないかのチェックを想定しています。 ↩︎

  7. 引数の値などからDBに保存するレコードに該当するインスタンスを作成するときに不正な値のインスタンスを作っていないかのチェックを想定しています。 ↩︎

Discussion