3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SpringBootで作成したREST APIのリクエストに対するバリデーションアノテーションの付け方

Last updated at Posted at 2021-12-12

SpringBootで作成したREST APIのリクエストに対してバリデーションチェックを行うにあたって、@Validated@Validの付与の仕方を整理するためにメモ。

動作環境

  • Spring Boot : 2.6.1
  • Dependenciesにspring-boot-starter-web,spring-boot-starter-validationが必要です(spring initializer)。

@PathVariable@RequestParamに対してのバリデーションチェック

  • クラスに対して@Validatedを付与。
  • 引数にバリデーション用のアノテーション(@Max等)を付与。

サンプルコード

SampleRestController.java
@Validated //ここに付与
@RestController
@RequestMapping("/validTest")
public class SampleRestController {

	@GetMapping("/pathValid/{limit}")
	public ResponseEntity<String> pathValid(@PathVariable("limit") @Min(1) @Max(5) Integer limit) {
		return ResponseEntity.ok("path validation OK!");
	}

	@GetMapping("/paramValid")
	public ResponseEntity<String> paramValid(@RequestParam("message") @Size(min = 1, max = 5) String message) {
		return ResponseEntity.ok("param validation OK!");
	}

}

動作確認

@PathVariable

正常値

> curl localhost:8080/validTest/pathValid/3
path validation OK!

異常値

> curl localhost:8080/validTest/pathValid/6
{"timestamp":"2021-12-12T12:47:06.657+00:00","status":500,"error":"Internal Server Error","path":"/validTest/pathValid/6"}

ログ

2021-12-12 21:47:06.647 ERROR 8812 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.validation.ConstraintViolationException: pathValid.limit: 5 以下の値にしてください] with root cause

javax.validation.ConstraintViolationException: pathValid.limit: 5 以下の値にしてください
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:120) ~[spring-context-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.13.jar:5.3.13]
	at com.example.demo.SampleRestController$$EnhancerBySpringCGLIB$$424b5c2e.pathValid(<generated>) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    ...

上記よりバリデーションチェックが有効になっていることがわかる。


@RequestParam

正常値

> curl localhost:8080/validTest/paramValid?message=hello
param validation OK!

異常値

> curl localhost:8080/validTest/paramValid?message=message
{"timestamp":"2021-12-12T12:48:51.798+00:00","status":500,"error":"Internal Server Error","path":"/validTest/paramValid"}

ログ

2021-12-12 21:48:51.797 ERROR 8812 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is javax.validation.ConstraintViolationException: paramValid.message: 1 から 5 の間のサイズにしてください] with root cause

javax.validation.ConstraintViolationException: paramValid.message: 1 から 5 の間のサイズにしてください
	at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:120) ~[spring-context-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:753) ~[spring-aop-5.3.13.jar:5.3.13]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:698) ~[spring-aop-5.3.13.jar:5.3.13]
	at com.example.demo.SampleRestController$$EnhancerBySpringCGLIB$$424b5c2e.paramValid(<generated>) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
    ...

@RequestBodyに対してのバリデーションチェック

  • 引数に対して@Validを付与。

サンプルコード

コントローラ

SampleRestController.java
@RestController
@RequestMapping("/validTest")
public class SampleRestController {

	@PostMapping("/reqBodyValid")
	public ResponseEntity<String> reqBodyValid(@RequestBody @Valid User user) {
		return ResponseEntity.ok("RequestBody validation OK!");
	}
}

バリデーション対象クラス

User.java
public class User {

	@Min(1)
	@Max(15)
	int id;

	@NotNull
	@Size(min = 1, max = 20)
	String name;

	@Min(1)
	int age;

    //以下getter,setter
}

動作確認

正常値

> curl -XPOST localhost:8080/validTest/reqBodyValid -H "Content-Type: application/json" -d '{\"id\":1,\"name\":\"user\",\"age\":20}'
RequestBody validation OK!

異常値

> curl -XPOST localhost:8080/validTest/reqBodyValid -H "Content-Type: application/json" -d '{\"id\":0,\"name\":\"userrrrrrrrrrrrrrrrr\",\"age\":0}'
{"timestamp":"2021-12-12T14:38:50.137+00:00","status":400,"error":"Bad Request","path":"/validTest/reqBodyValid"}

ログ

2021-12-12 23:38:50.136  WARN 20332 --- [nio-8080-exec-5] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<java.lang.String> com.example.demo.SampleRestController.reqBodyValid(com.example.demo.User) with 2 errors: [Field error in object 'user' on field 'age': rejected value [0]; codes [Min.user.age,Min.age,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.age,age]; arguments []; default message [age],1]; default message [1 以上の値にしてください]] [Field error in object 'user' on field 'id': rejected value [0]; codes [Min.user.id,Min.id,Min.int,Min]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.id,id]; arguments []; default message [id],1]; default message [1 以上の値にしてください]] ]

上記よりバリデーションチェックが有効になっていることがわかる。

おわりに

バリデーションチェックに関して検索すると、全部のせみたいな感じのサンプルコードが多く、整理してみると付け方を間違えているものがあった。

参考資料

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?