Hi,
I'm interested in to validate the request/response of REST services. There is no problem validating the request parameters using webMvc or webFlux, but not the response, using webMvc the response validation is executed in the MethodValidationInterceptor
, but there is no equivalence using webFlux, so the response is not validated. I attached two equivalent applications using webMvc and webFlux to show this behaviour (demos.zip).
The request parameters are validated two times in webMvc, one by the MethodValidationInterceptor
and another in the RequestResponseBodyMethodProcessor
. The MethodValidationInterceptor
validates parameters and response, but the RequestResponseBodyMethodProcessor
only validates parameters, so I need to load MethodValidationInterceptor
to achieve my goal. In webFlux only is validating the RequestBodyMethodArgumentResolver
, and this validates only the parameters not the response, and I couldn't find a reactive equivalence to the MethodValidationInterceptor
, is there any other option to validate the response value using webFlux?
Thxs for your time.
Comment From: simonbasle
Spring WebFlux doesn't support return value validation on reactive controllers. There is currently no easy way of dealing with the reactive return value and applying Bean Validation to it, but here's an alternative:
What you could do is extract the MyEntity
creation logic outside the Controller
and into a @Service
, since Spring supports validation of Services. There the validation would apply to an imperative method which returns a MyEntity
directly, so it would work out of the box even if the service invocation is deferred inside the Mono
.
I have slightly simplified your example and applied this logic, which looks like the following:
@Service
@Validated
public static class EntityCreationService {
@Valid MyEntity create(int id) {
if (id == 0) {
return new MyEntity(-1L, "1234567890");
}
else {
return new MyEntity((long) id, "correct" + id);
}
}
}
@RestController
public class ValidatedController {
@Autowired
EntityCreationService entityCreationService;
@GetMapping(path = "/test/{id}")
public Mono<MyEntity> test(@PathVariable int id) {
return Mono.defer(() -> Mono.just(entityCreationService.create(id)));
}
}