Validate Request Body and Parameter in Spring Boot

Eric Cabrel Tiogo
6 min readApr 22, 2022

--

Photo by FLY:D on Unsplash

Never trust user input

A typical Web application workflow is: to receive a request with some inputs, perform a treatment with the input received, and finally return a response. When developing our application, we usually test only the “happy path” or think the end-user can’t provide bad inputs. To prevent that, we can perform a validation of the inputs before processing the request.

Spring offers an elegant way to do that, and we will see how to do it.

The use case

We need to build a system where a user can make a reservation for a room in a hotel. The user must provide his address information when registering. The possible actions are

  • Register a user with his address.
  • Make a reservation for an existing user.

Beneath is the Entity-Relation diagram of the system made with drawSQL:

Minimal entity-relation diagram of a hotel reservation system

For this tutorial, you need Java 11 and MySQL installed on your computer or Docker if you don’t want to install MySQL on your computer. Indeed, you can start a Docker container from MySQL Docker image. It will be enough to achieve the goal.

docker run -it -e MYSQL_ROOT_PASSWORD=secretpswd -e MYSQL_DATABASE=hotels --name hotels-mysql -p 3307:3306 mysql:8.0

Setup the project

Let’s create a new spring project from start.spring.io with the required dependencies.

Initialize the Spring Boot project with required dependencies

The dependency responsible for input validation is Bean Validation with Hibernate validator. This library has no link with Hibernate’s persistence aspect, provided here by Spring Data JPA.

Open the project in your IDE and set the server port and database credentials in application.properties file.

Create entities and services

We need to create the entities User, Address, and Reservation. For each entity, we will create the related Repository and Service. Since it is not the main topic of this tutorial, find the code of these files in the Github repository:

  • Entities are inside the package models.
  • Entities Repositories are inside the package repositories.
  • Services are inside the package services.

Register a user

We need to create the endpoint to handle this action and define the object that will receive the input required to create the user.

Create the model for the request body

When registering a new user, we also provide information on his address in the body. We need to structure our object to handle that by creating a class called AddressDTO that will hold all properties for the address, and there will be a property of type AddressDTO inside the class RegisterUserDTO.

The class names are suffixed with DTO (Data Transfer Object) because they transport data from one layer (controller) to another layer (persistence). A common use case of his usage is when we need to apply some transformation data before passing them to the other layer. I will write a more detailed post about it later.

Create a package called dtos inside the package models, then create two classes AddressDto.java and RegisterUserDto.java.

Add validation

Hibernate Validator provides built-in constraints that will use to validate our input. To see the full list check out this link.

AddressDto.java

RegisterUserDto.java

Create a route to test registration

Let’s create an endpoint responsible for registering a new user. Create a package called controllers, then create a controller called UserController.java. Add the code below:

The most important part of the code above is the use of the @Valid annotation.

When Spring finds an argument annotated with @Valid, it automatically validates the argument and throws an exception if the validation fails.

Run the application and make sure there is no error at the launch.

Test with postman

Our app launched; open postman and send a request with all the input to null and see the result.

Test the route with Postman

We got an HTTP status 400 with the message “Bad Request,” nothing more 🙁. Let’s check the application console to see what happened:

Exception thrown logged in the SpringBoot console

As we can see, an exception of type MethodArgumentNotValidException has been thrown, but since the exception is not caught anywhere, the response fallback to a Bad Request.

Handle validation error exception

Spring provides a specialized annotation of @Component called @ControllerAdvice which allows handling exceptions thrown by methods annotated with @RequestMapping and similar in one global single component.

Create a package called exceptions, then create a file called GlobalExceptionHandler.java. Add the code below:

Launch the app and make the call on Postman.

Test birth date in the feature and the ZIP code with alphabetical letters (The ZIP code in France can’t have letters).

Let’s do the same by creating CreateReservationDto.java then add the code below:

Find the code for ReservationController.java in the source code repository.

Test with postman

Validation input errors when creating a reservation

Validate Request parameter

Now, we want to retrieve a reservation through the generate unique code.

Retrieve of all reservations from Postman

The endpoint will look like this: /reservations/RSV-2021–1001. Since the user provided the reservation’s code, we need to validate it to avoid making an unnecessary database call cause if the code provided is not in this good format, we are sure it will not be found in the database.

When creating a route with Spring, adding an annotation rule to validate the input is possible. In our case, we will apply a Regex the validate the format of the reservation’s code.

Inside the ReservationController.java, add the code below:

Define a new route inside the ReservationController.java

If you run the application and call the route with a bad code, nothing happens because we need to tell the controller to validate parameters with annotation rules. We achieve that with the annotation @Validated, which is added to the ReservationController class:

Add @Validated annotation on the class ReservationController

Now run the application and test with a bad reservation code.

Ooops!!! The application throws an internal server error, and the console looks like this:

The validation failed as expected, but a new exception of type ConstraintViolationException has been thrown. Since it is not caught by the application, an internal server error is returned. Update the GlobalExceptionHandler.java to catch this exception:

GlobalExceptionHandler.java updated to catch ConstraintViolationException

Launch the application and test. Now we got an error with a clear message.

Conclusion

We can implement a solid validation that made our backend more resilient to bad inputs coming from users. Throughout the tutorial, we used predefined validation rules, but we can also create our custom validation rule for a specialized use case. Check out this tutorial to learn how.

Find the code of this project in the Github repository.

This post was originally published on my blog https://blog.tericcabrel.com where I write about building the Backend applications.

Please, follow me on Twitter or subscribe to my newsletter to get notified when I publish a new post.

--

--

Eric Cabrel Tiogo

Software Engineer — Technical Blogger — Open Source enthusiast — Contributor and Mentor at OSS Cameroon