@Valid? @Validated? Which one you are using?
In spring boot application to validate the input data in your rest endpoints we have multiple ways and one of which using spring validation.
In a application we usually first perform the validation on the data at frontend which we are sending to backend but it the responsibility of backend developer to validate the incoming data again in case our frontend fails validate it and sends the invalidate data to backend which could cause a serious problem later.
With spring validation you can validate your input data to your rest endpoint very easily and efficiently either for your payload data or the query param or path variable whichever it is.
Let’s get started with it.
create a spring boot application with below dependencies.
If you don’t want to store your data in DB you can avoid the dependencies of data jpa, h2 and lombok also if you prefer to write the setter and getter methods manually.
Creating the required classes and methods.
create the project structure for your application with RestController classes and other supporting classes.
you can find all the code used in this article in GitHub repository for which the link is provided at the bottom of the article.
below is the Student entity class which we are using to persist our data to h2 DB and also the class where we are mapping our payload data and hence the class where we need to apply the validation.
below is the Student class with spring validation constraints.
you can find all the available spring validation constrains in below api docs
student details are coming from a request as payload which is processed by our rest endpoint in the StudentRestController.
to apply the validation constraints on input we need to add the @valid annotation on your Request body otherwise it won’t apply the validation constrains which you have used on your Student class.
let’s see how our api responds to the api call with invalid data.
Well we got the error. why is that so?
as you can see in the above request body the age I have specified is 10 which is violation of constraint for @Min(17) constraint hence it gives bad request error.
same is true for all the validation constrains we have used on our Student class it can be either for email or section.
put the correct data and try again to see if it works.
as you can see above it works fine with correct data.
What about validation for composite properties ?
that was pretty easy right? well then how do we proceed when our class contains the composite property and that composite property again contains the validation constrains?
take an example here, suppose your student class has a composite variable variable Address and Address class contains validation for it’s own properties like street no, pinCode etc. do we need follow same approach as above.
the validation approach for composite property is same as previous just that you need to add @Valid annotation on the top of your address property to perform the validation of the address class properties.
suppose I’m adding below property in my Student class
@OneToOne(cascade = CascadeType.ALL,orphanRemoval = true)
@NotNull(message = "address cannot be null")
private Address address;
and student class again contains validation for it’s own properties as below.
as you can see now it’s performs the validation for address class properties also as we have given city as empty value.
now try to give correct values and check again
as you can see above with correct data it’s processing our data.
What about the @RequestParam and @PathVariable how do we validate it ?
It’s very simple to perform the validation on path variable and query parameter.
we just need to add the constraints on the parameters and then add one annotation @Validated on the top of our rest class.
remember if we don’t add the @Validated annotation on the top of our rest class it won’t perform the validation for path variable and query parameter.
now try to make a call with invalid data.
well it fails with because the status is not according to Pattern constraint we have specified so it won’t.
but with right data it will work as it supposed to.
Did you observe above image?
if you observe above image you can see that the error status it is returning is 500 but when error is thrown for property constraints it gives 400 but now 500, why is it so.
when the exception is throws for class fields constraints then the exception thrown is MethodArgumentNotValidException but the exception thrown for query param or path variable constrains is ConstraintViolationException and they both have different error status codes.
Can we customise the exception message which we are getting for validation?
yes, we can customise for that we need to write our own Exception handler with customised error model.
you can follow the below approach for that.
Example of customise error response for invalid data.
as you can see the error message is according to our requirement.
Refer below GitHub for above example.