Validating Request Data — Validating In Service Layer
If you want to do validation in the service layer, which is a good practice, Spring Boot supports it very well. Instead of using the @Valid annotation in the controller, you’ll need to do it in the service, as below:
Don’t miss the class level @Validated annotation.
So, how does it work?
Spring Boot auto configures a MethodValidationPostProcessor component, which validates all method parameters that are annotated with @Valid inside all components that are annotated with @Validated. It throws a ConstraintViolationException exception in case of errors.
Our job then becomes handling the exception and translating that to a suitable error response. While we've already discussed how to handle exceptions previous section, let's now discuss how to translate a ConstraintViolationException to a suitable response body.
How to translate ConstraintViolationExceptions
Getting the validation errors
ConstraintViolationException’s getConstraintViolations() method returns the errors as a set of ConstraintViolations. So, we should transform those ConstraintViolations into a simple structure and return that in the response.
Structure to send to the client
A simple structure for returning validation errors to the client could look like this:
It's an array of error messages. Each error message has
- A field containing the path of the field. Nested fields can have multiple dots in them, like user.address.lane in the fifth case above. In case the error is not related to a specific field, but is a form-level global error, as in the fourth case above, field can be just the object name, null, or something unknown.
- A code containing the error code.
- A message containing an internationalized error message.
These error messages can be structured as a simple class as below:
Converting ConstraintViolations to FieldErrors
ConstraintViolation has the following attributes:
The propertyPath above is of the format methodName.objectName.fieldName. We won’t need the methodName prefix when sending it to the client. To strip it out, the code snippet below can be used:
So, in summary, the method below would convert a ConstraintViolation to a FieldError:
Using the above method, a set of ConstraintViolations can then be converted to a list of FieldErrors as below: