I am trying to use the @Valid
annotation to validate outgoing, (not incoming) request payload body.
There is this construct to validate incoming request's body payload in Spring Boot:
@RestController
class FieldValidationController {
@PostMapping("/validate")
String question(@Valid @RequestBody SomeRequest someRequest) {
return "please validate the field";
}
}
public record SomeRequest(@Email String email) { }
This would ensure that an incoming request to this web API would be validated (in this case, that the incoming request's email field is indeed an email).
Is it possible to do the same, not for incoming, but for outgoing requests?
With the same construct, I did this:
@HttpExchange(accept = "application/json")
public interface FooHttpExchange {
@PostExchange("/outgoing")
String question(@RequestBody @Valid final OutgoingFoo foo);
}
public record OutgoingFoo(
int score,
@Email
String email
) {
}
And when trying to send the request, I do this:
String s = fooHttpExchange.question(foo);
OutgoingFoo foo = new OutgoingFoo(42, "thisisnotanemailpleasefaildontsendtherequest")
As you can see in the outgoing object, this is violating the rule.
I would have expected this to fail before sending the request.
I understand I could have written some custom if statements after the construction of my outgoing object. And this is not a question about email specifically, but the @Valid
annotation in general.
How to use it for outgoing (not incoming) request validation?
Don't forget to add the @Validated
annotation to the target classes:
@HttpExchange
annotated interface orclass
that implements it, same asI will explain Spring's requirements for bean-validation and possible restrictions for HTTP interfaces below.
According to the Spring Framework reference documentation on Java Bean Validation, section Spring-driven Method Validation:
To be eligible for Spring-driven method validation, target classes need to be annotated with Spring’s
@Validated
annotation, which can optionally also declare the validation groups to use.
This annotation @Validated
should be used for example in your controller class, or like given in the example of section "Customizing Validation Errors" in the same docs, at the service class:
record Person(@Size(min = 1, max = 10) String name) {
}
@Validated
public class MyService {
void addStudent(@Valid Person person, @Max(2) int degrees) {
// ...
}
}
Note: Those examples are annotated class
es, not interface
s. This could make a difference.
@HttpExchange
In Spring Frameworks's HTTP Interface, i.e. Jave interface
s annotated with @HttpExchange
, same bean-validation logic would make sense.
But section 1.3.1. Method Parameters the annotation @Valid
is not listed, although it could be applied to any parameter, theoretically.
Still, stictly speaking, then the requirement for Spring's bean-validation as given above:
target classes need to be annotated with Spring’s
@Validated
annotation
can probably not be applied to an interface
itself. But, it should work on a class
if this class implements the HTTP interface, i.e. the interface
annotated with @HttpExchange
.