Learn to validate the request body (JSON posted to Spring REST API). Also validate @PathVariable and @RequestParam parameters in resource URIs using hibernate validator 2.x.
In this spring rest validation example, we will be adding validations in REST APIs created for CRUD example.
1. Request body validation using hibernate validator
1.1. Maven dependency
< dependency > < groupId >org.hibernate.validator</ groupId > < artifactId >hibernate-validator</ artifactId > < version >6.0.16.Final</ version > </ dependency > |
This transitively pulls in the dependency to the Bean Validation API (
javax.validation:validation-api
:2.0.1.Final).1.2. Enable bean validation
In Spring boot, the bean validation is automatically enabled if any JSR-303 implementation (like hibernate validator 2.0) is available on the classpath.
If we are not using spring boot, we need to add LocalValidatorFactoryBean.
@Bean public javax.validation.Validator localValidatorFactoryBean() { return new LocalValidatorFactoryBean(); } |
< bean id = "validator" class = "org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> |
1.3. Add bean validation annotations
Add the bean validation annotations in model classes which will store the request body data such as
@NotEmpty
and @Email
.import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.Email; import javax.validation.constraints.NotEmpty; @Entity @Table (name = "tbl_employee" ) public class Employee implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; @NotEmpty (message = "First name must not be empty" ) private String firstName; @NotEmpty (message = "Last name must not be empty" ) private String lastName; @NotEmpty (message = "Email must not be empty" ) @Email (message = "Email must be a valid email address" ) private String email; public Employee() { } //setters and getters @Override public String toString() { return "EmployeeVO [id=" + id + ", firstName=" + firstName + ", lastName= " + lastName + " , email= " + email + " ]"; } } |
1.4. Handle ConstraintViolationException
In case of any validation failures, Spring will throw ConstraintViolationException. We can handle it any return a meaningful JSON error response from using
@ExceptionHandler
.@ControllerAdvice @ResponseBody public class CustomExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler (ConstraintViolationException. class ) public final ResponseEntity<ErrorResponse> handleConstraintViolation( ConstraintViolationException ex, WebRequest request) { List<String> details = ex.getConstraintViolations() .parallelStream() .map(e -> e.getMessage()) .collect(Collectors.toList()); ErrorResponse error = new ErrorResponse(BAD_REQUEST, details); return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST); } } |
2. Query and path parameter validation
In Spring REST, parameters in request URI are captured via @PathVariable and all query parameters via @RequestParam.
Please note that maven dependency shall be added and
ConstraintViolationException
should be handled as described above.2.1. Enable validation
Query and path parameter validation is not straightforward. We need to explicitly create bean
MethodValidationPostProcessor
which will process the @Validated annotation.< bean class = "org.springframework.validation.beanvalidation.MethodValidationPostProcessor" /> |
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor(); } |
2.2. Add validation to parameters
- use JSR-303 annotations as described above.
- use
@Validated
annotation on top of controller so it is applicable to all methods in it.
@RestController @RequestMapping (value = "/employee-management" , produces = { MediaType.APPLICATION_JSON_VALUE }) @Validated public class EmployeeRESTController { @GetMapping ( "/employees/{id}" ) Employee getEmployeeById( @PathVariable @Min (value = 1 , message = "id must be greater than or equal to 1" ) @Max (value = 1000 , message = "id must be lower than or equal to 1000" ) Long id) { return repository.findById(id) .orElseThrow(() -> new RecordNotFoundException( "Employee id '" + id + "' does no exist" )); } } |
3. Demo
3.1. Request body validation
//1
HTTP POST : http: //localhost:8080/SpringRestExample/api/rest/employee-management/employees/ Headers: AUTH_API_KEY: abcd123456 Content-Type: application/json Body: { "firstName" : "" , "lastName" : "Gupta" , "email" : "abc@gmail.com" } |
{ "message" : "BAD_REQUEST" , "details" :[ "First name must not be empty" ] } |
//2
HTTP POST : http: //localhost:8080/SpringRestExample/api/rest/employee-management/employees/ Headers: AUTH_API_KEY: abcd123456 Content-Type: application/json Body: { "firstName" : "" , "email" : "abc@gmail.com" } |
{ "message" : "BAD_REQUEST" , "details" : [ "First name must not be empty" , "Last name must not be empty" ] } |
3.2. Path param validation
//1
HTTP GET : http: //localhost:8080/SpringRestExample/api/rest/employee-management/employees/0 Headers: AUTH_API_KEY: abcd123456 Content-Type: application/json |
{ "message" : "BAD_REQUEST" , "details" :[ "id must be greater than or equal to 1" ] } //2 HTTP GET : http: //localhost:8080/SpringRestExample/api/rest/employee-management/employees/5000 Headers: AUTH_API_KEY: abcd123456 Content-Type: application/json |
{
“message”:”BAD_REQUEST”,
“details”:[“id must be lower than or equal to 1000”]
}
“message”:”BAD_REQUEST”,
“details”:[“id must be lower than or equal to 1000”]
}
No comments:
Post a Comment