Spring REST Request Body and Parameter Validation Example

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”]
}

Happy Learning !!

Leave a Reply

3 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions, and frequently asked interview questions.