Validate Request Body in RESTful Web Service

In this tutorial, you will learn how to validate the request body of an HTTP Post request sent to a RESTful Web Service endpoint built with Spring Boot.

Request Body JSON

Let’s say you have a RESTful Web Service endpoint that accepts HTTP post requests with the following JSON payload:

{
    "firstName": "Sergey",
    "lastName": "Kargopolov",
    "password":"1234765432",
    "email":"[email protected]"
}

You would like to validate this request body and make sure that required information is not missing and that, for example, the email address is of a correct format.

Web Service Endpoint

For you to be able to receive the above-mentioned JSON payload in a RESTful Web Service, your Rest Controller, and the request mapping will look something like this:

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping(produces = {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
    public UserRest createUser(@Valid @RequestBody UserDetailsRequestModel requestUserDetails) {
        
        UserRest returnValue = new UserRest();
        returnValue.setFirstName("Sergey");
        returnValue.setLastName("Kargopolov");

        return returnValue;
    }

}

Please have a look at the method signature that handles the HTTP Post Request. It contains three important pieces of information:

  • @Valid annotation which is required to kick in the validation of the information received,
  • @RequestBody annotation which signifies that the payload in the body of the request will be mapped to a model class which it annotates,
  • and the UserDetailsRequestModel model class which can be named differently but what is important is that this model class contains getters and setters methods for class fields which should match the JSON payload keys. An example of this model class is below:

Model class

For the framework to be able to map the above-mentioned JSON payload to a Java class, we need to create a Java bean class which contains class fields for each of the key in the JSON payload. Like so:

package com.appsdeveloperblog.app.ws.ui.request;

public class UserDetailsRequestModel {
    private String firstName;
    private String lastName;
    private String email;
    private String password;

  
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastName() {
        return lastName;
    }
 
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }

 
    public String getPassword() {
        return password;
    }

 
    public void setPassword(String password) {
        this.password = password;
    }
    
}

The above Java bean class does not have any validation yet. But it can be used to accept information which the JSON payload sent in the body of HTTP POST request carries. Now let’s validate the fields and make sure that firstName and lastName are not empty and that the email address is of a valid format.

Validate Java Bean Fields with Validation Constraints

To validate the JSON payload sent in the HTTP POST request body and then mapped to the above Java bean class, we will use Hibernate Validator Constraints which are already included in our project if you have used Spring Boot to create it and you have the spring-boot-starter-web in your pom.xml file.

Note: If your project does not compile because the below validation annotations could not be found, then add the following dependencies to the pom.xml file of your project.

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Additionally to adding the above validation dependency, add the following two configuration properties to an application.properties file.

server.error.include-message=always
server.error.include-binding-errors=always

There are many validation constraints available to use but I will use just the ones needed for this example:

  1. @NotNull
  2. @Size
    1. @Size(min=8,  message=” Password must be greater than 8 characters “)
    2. @Size(max=16, message=” Password must be greater than 16 characters”)
    3. Or you can use min and max together like so:
      @Size(min=8, max=16, message=” Password must be equal to or greater than 8 characters and less than 16 characters”)
  3. @Email

Have a look at the below model class now annotated with validation constraints.

package com.appsdeveloperblog.app.ws.ui.request;

import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

 
public class UserDetailsRequestModel {
    @NotNull(message="First name cannot be missing or empty")
    @Size(min=2, message="First name must not be less than 2 characters")
    private String firstName;

    @NotNull(message="Last name cannot be missing or empty")
    @Size(min=2, message="Last name must not be less than 2 characters")
    private String lastName;

    @Email
    private String email;

    @NotNull(message="Password is a required field")
    @Size(min=8, max=16, message="Password must be equal to or greater than 8 characters and less than 16 characters")
    private String password;

    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

If one of the fields fails the validation, a 400 Bad Request HTTP status code will be returned in Response. For example, if the email address was not properly formatted in the above JSON Payload the following response will be sent back:

{
    "timestamp": "2018-09-21T14:52:14.853+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "Email.userDetailsRequestModel.email",
                "Email.email",
                "Email.java.lang.String",
                "Email"
            ],
            "arguments": [
                {
                    "codes": [
                        "userDetailsRequestModel.email",
                        "email"
                    ],
                    "arguments": null,
                    "defaultMessage": "email",
                    "code": "email"
                },
                [],
                {
                    "arguments": null,
                    "defaultMessage": ".*",
                    "codes": [
                        ".*"
                    ]
                }
            ],
            "defaultMessage": "must be a well-formed email address",
            "objectName": "userDetailsRequestModel",
            "field": "email",
            "rejectedValue": "test [email protected]",
            "bindingFailure": false,
            "code": "Email"
        }
    ],
    "message": "Validation failed for object='userDetailsRequestModel'. Error count: 1",
    "path": "/users"
}

@NotNull, @NotEmpty and @NotBlank

You could also use @NotNull, @NotEmpty or @NotBlank to validate if a Bean property is not empty. Although these three annotations sound like they all do the same thing there is a difference between them.

  • @NotNull – Checks that the annotated value is not null. But it can be empty. An annotated value can be of any type(String or an Array or a Collection …),
  • @NotEmpty – Checks whether the annotated element is not null nor empty. An annotated value can be CharSequence, Collection, Map, and arrays,
  • @NotBlank – Checks that the annotated character sequence is not null and the trimmed length is greater than 0. The difference to @NotEmpty is that this constraint can only be applied on strings and that trailing whitespaces are ignored.

Video Tutorial

I hope this tutorial was helpful to you.

If you are interested to learn more about building RESTful Web Services with Spring Boot, check the below video courses. One of them might be exactly what you are looking for.


Leave a Reply

Your email address will not be published. Required fields are marked *