Eyas Mattar
3 min readMar 26, 2019

Spring Boot Request Validation & Validators in RESTful Services

We want to build a RESTful service which will serve multiple requests from different hosts.

The server is the core and the most reliable component of any application. The server should provide the most reliable, valid and correct data possible so the UI (View Layer- User Interface) or any other component of the application can present, and the server should do that by applying good and powerful validations on the data it stores, retrieves and changes.

The server, generally, is the entry point of the databases- where reside our precious and valuable data.
When we execute a CRUD operation by the server, we want to make sure we store “valid data”.
“valid” data means that the data we store follows our Data Domain set of rules that were set by the application administrator.

Spring Boot provides a straightforward way to implement our validation

Entity

We will start by defining our @Entity

@Entity
@Table(name="Category")
public class Category {
private Integer categoryId;

private String name;

private String description;

}

javax.persistence.Entity @Entity is indicating that it is a JPA entity.

javax.persistence.Table @Table is indicating that it is mapped to a table called Category.

Let’s define our columns and add some constraints.

@Entity
@Table(name="Category")
public class Category {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer categoryId;

@Column(name = "name", nullable=false, length=200, unique = true)
private String name;

@Column(name = "description", nullable=false, length=600)
private String description;

}

We defined THREE columns for table Category:

@Id indicates that this column is the id categoryId is the

@GenerationValue(strategy = GenerationType.AUTO) defines the strategy for generating the id, in this case it is AUTO generated and incremented.

Validation

Let’s dig into the validation

@Entity
@Table(name="Category")
public class Category implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer categoryId;

@NotNull(message="Name is required")
@Size(min=4, message="Name: minimum 4 characters")
@Pattern(regexp="^[A-Z a-z]+", message="Name: Illegal characters")
@Column(name = "name", nullable=false, length=200, unique = true)
private String name;

@NotNull(message="description is required")
@Size(min=4, message="description: minimum 4 characters")
@Pattern(regexp="^[A-Z a-z]+", message="description: Illegal characters")
@Column(name = "description", nullable=false, length=600)
private String description;

}
  • Category name and category description are mandatory fields so we declare them with @NotNull annotation
  • The @Size annotation takes min and max values and it limits the field length
@Size(min=4, message="Name: minimum 4 characters")

We want to limit the name and the description to minimum 4 characters.

  • @Pattern enables you to limit user input to some specific pattern using RegExp

For the full list of the Built-in Bean Validation you can check the documentation:

To catch invalid inputs we need a @ControllerAdvice that will catch the MethodArgumentNotValidException Exception and customize our response.

@ControllerAdvice
public class ValidationErrorResponse extends ResponseEntityExceptionHandler {

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
List<String> errors = new ArrayList<String>();
for (FieldError error : ex.getBindingResult().getFieldErrors()) {
errors.add(error.getField() + ": " + error.getDefaultMessage());
}
for (ObjectError error : ex.getBindingResult().getGlobalErrors()) {
errors.add(error.getObjectName() + ": " + error.getDefaultMessage());
}

return new ResponseEntity<Object>(new GeneralResponse(errors, "error"), HttpStatus.OK);
}
}

ex.getBindingResult().getFieldErrors() will return the list of the validation errors.

error.getObjectName() + “: “ + error.getDefaultMessage()

Here we only mapped the errors and simplified our response to return only the objectName and the defaultMessage of the error.

In the handleMethodArgumentNotValid function you can customize the response as you wish, the above code is only example of one mapping and should not to be considered as a rule.

No responses yet