1
votes

I am new to reactive programming. To get my hands on i am trying to build a simple rest api but with request validation and db operations.

here are my steps i would like to do.

  1. validate incoming request parameter
  2. after verified keep continue chain and fetch from db
    • If user not exists in db return some error response
    • If user exists return success response with user name

note: request and response represented by classes (UserRequest and UserResponse). DB = Mongo using reactive drivers.

I have done the validation work but now i am confuse how to continue and what is the proper way in reactive programming.

@Component
public class UserController {

    @Autowired
    private UserRepository userRepository; // repo has find by id method which returns Mono<User>

    public Mono<ServerResponse> handleUserRequest(ServerRequest serverRequest) {

        Mono<UserRequest> request = validateRequest(serverRequest);
        
        // what should i do here like now i would like to fetch user from db

        return ServerResponse.ok().body("Welcome", String.class);
        // how would i return "Welcome <username>";
    }

    private Mono<UserRequest> validateRequest(ServerRequest request) {

        Mono<UserRequest> userRequest = Mono.just(new UserRequest());

        Mono<UserRequest> validateUser = userRequest
                .map(req -> { //validate id
                    Optional<String> userid = request.queryParam("userid");

                    if (user.isPresent() && ObjectId.isValid(userid.get())) {
                        return req.setUserid(userid.get());
                    }

                    throw new RequestEntityValidationException("Invalid user");
                });


        return validateUser;
    }
}

Also is there any side by side tutorial like which show general code snippets in imperative then in reactive.

2

2 Answers

0
votes

The main idea of reactive programming is to work with flow chain all the time. According to the db data fetching you can take data with userRepository.findUserById(id) or similar to this. As a result you will receive Mono<User> that can have value or not - then it is an empty Mono.

To handle that case I would suggest code that in this way:

public Mono<ServerResponse> handleUserRequest(ServerRequest serverRequest) {
    return validateRequest(serverRequest)
            .flatMap(userRequest -> userRepository.findUserById(userRequest.getUserId())
                    .switchIfEmpty(Mono.error(new RuntimeException("Not found")))
            )
            .flatMap(user -> ServerResponse.ok().body("Welcome " + user.getUsername(), String.class));
}

You can adjust your validateRequest method to be more in functional way (without isPresent check):

private Mono<UserRequest> validateRequest(ServerRequest request) {
    return Mono.just(request)
            .map(req -> request.queryParam("userId")
                    .map(UserRequest::new)
                    .orElseThrow(() -> new RuntimeException("Invalid user"))
            );
}
0
votes

There's no built in way when using functional reactive HTTP endpoints but you might try https://github.com/making/yavi

You can use @Valid for Spring Webflux HTTP @Controller