Request Validation With Spring WebFlux
Introduction
Validation is an integral part of the API request lifecycle. Validating the incoming data is a best practice for any API because of the following reasons.
Reduce the complexity of logic at lower layers.
If the API accepts the HTTP request from the API consumer without validation, the API has to check for the empty, malformed values all along with the business logic. This will ultimately affect the code readability negatively as it shifts the reader’s focus away from the core business logic.
Improve the security of the system
The data from the web frontend, mobile, or command-line client can be untrusted. APIs get exploited by hackers every day for the security loopholes they possess. The incoming data must be verified for its specific format and integrity before it goes deep into the system.
The implementation
Let’s consider a straightforward example and identify how we can use the Spring framework capabilities to validate and respond with meaningful errors to the API consumer when the specific rules get violated.
Contract
The API resource provides a simple functionality where it formats the given name into a single line.
Setting the Dependency
To start with, you would need a project set up with a Spring WebFlux enabled SpingBoot Project; there are plenty of examples online; hence, we will not focus on it. The important thing is to have spring-boot-starter-validation dependency on the project class-path. (This article assumes your project use the spring boot dependency management plugin; otherwise, you would need the version on the dependency declaration)
'org.springframework.boot:spring-boot-starter-validation'
Adding Annotations
Then annotate your request object with the constrained which you would like to have as follows. For this example, we are using a few simple constraints. Note the annotations can have a custom error message; this will come in handy later.
Construct Controller
And next step is to configure your controller as follows. There are few essential things that you need to know here.
- Note the @Valid annotation at the argument parameter, which informs Spring that the object denoted by @RequestBody needs to be validated using JSR 380 annotations.
- Note that by declaring FormatNameRequest as reactive types, Spring provides fully non-blocking reading and (client-to-server) streaming.
- The validation would not happen if you pass through the object without doing anything with it; after all, it is a reactive pipeline; hence, there will be no reaction in the absence of use.
- When the constrained violation happens, Spring will emit an error signal with WebExchangeBindException, which can be handled and customised using onErrorResume() with a type match.
Handling WebExchangeBindException
The final step is to interrogate the WebExchangeBindException to extract the error details and use those to create a proper error message as per our contract.
The API method .getFieldErrors() returns a list of FieldError objects which contain the information about the constrained violation.
Note that the fieldError.getDefaultMessage(), give access to the message we setup at the annotation set up
@NotNull(message = "Title cannot be null")
And the rest of the logic is self-explanatory.
Error Response
Conclusion.
Enabling validation and handling the errors gracefully with meaningful messages as easy as that when we get the support from JSR validations and Spring framework support.