Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validating request body in Spring WebFlux

How do you validate a request DTO in a reactive Spring Web application?

In a regular Spring Web application, you would simply annotate the DTO with things like @Size, @Email and then put @Valid beside the controller method parameter, like so:

 import jakarta.validation.constraints.*;

    public class UserSignupRequestDTO {

        @NotBlank(message = "Email cannot be blank")
        @Email(message = "Email should be valid")
        private String email;

        @NotBlank(message = "Password cannot be blank")
        @Size(min = 8, message = "Password must be at least 8 characters long")
        private String password;
}
    @RestController
    public class SignupController {

        @PostMapping("/signup")
        public ResponseEntity<?> signup(@Valid @RequestBody UserSignupRequestDTO signupRequest) {
            // ...
        }
    }

However, it's not an option for a reactive handler:

@Configuration
public class RouterConfig {
    private final TokenHandler tokenHandler;

    public RouterConfig(TokenHandler tokenHandler) {
        this.tokenHandler = tokenHandler;
    }

    @Bean
    @RouterOperation(beanClass = TokenHandler.class, beanMethod = "signUp")
    public RouterFunction<ServerResponse> signUpRoute() {
        return RouterFunctions.route()
                .POST("/signup", tokenHandler::signUp)
                .build();
    }
}
// TokenHandler implementation
    @Override
    public Mono<ServerResponse> signUp(ServerRequest request) {
        return request.bodyToMono(UserSignupRequestDto.class) // this has to be validated
                .map(userMapper::toUser)
                .map(userService::save)
                .map(tokenService::generateTokenFor)
                .transform(jwt -> ServerResponse.status(HttpStatus.CREATED).body(jwt, String.class));
    }

What is Spring's suggested way of validating a request body DTO in such circumstances? I would still like to involve Jakarta's validation annotations without, obviously, writing any annotation-processing code myself.

like image 794
Sergey Zolotarev Avatar asked Aug 06 '26 17:08

Sergey Zolotarev


1 Answers

As I've said in my comment, you can inject a Validator. The following successfully throws a ConstraintViolationException:

// TokenHandler implementation
    @Autowired
    private Validator validator;

    @Override
    public Mono<ServerResponse> signUp(ServerRequest request) {
        return request.bodyToMono(UserSignupRequestDto.class) // this has to be validated
                .map(this::validate)
                .map(userMapper::toUser)
                .map(userService::save)
                .map(tokenService::generateTokenFor)
                .transform(jwt -> ServerResponse.status(HttpStatus.CREATED).body(jwt, String.class));
    }

    private <T> T validate(T object) {
        Set<ConstraintViolation<T>> violations = validator.validate(object);
        if (violations.isEmpty()) {
            return object;
        }
        throw new ConstraintViolationException(violations);
    }

Without any error handling in place that doesn't get turned into a nice error message, but that's a next step.

like image 61
Rob Spoor Avatar answered Aug 09 '26 07:08

Rob Spoor



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!