Seffy
Seffy

Reputation: 1085

Spring WebFlux - how to get data from request?

Trying to migrate my Spring Boot app to WebFlux, I started to convert the api tier while leaving the repository intact (i.e. db access is sync and blocking). I'm facing issues how to get data from the Mono/Flux types and forward them to the repository.

Consider the following

@POST
@Path("/register")
public String register( String body ) throws Exception
{
    ObjectMapper objectMapper = json();

    User user = objectMapper.readValue( body, User.class );

    int random = getRandomNumber( 111111, 999999 );

    String uuid = null;

    //first, check if user already did registration from that phone
    UserDbRecord userDbRecord = UserDAO.getInstance().getUserByPhone( user.phone );

    if( userDbRecord != null )
    {
        logger.info( "register. User already exist with phone: " + user.phone + ", id: " + userDbRecord.getId() );

        uuid = userDbRecord.getToken();
    }
    else
    {
        uuid = UUID.randomUUID().toString();
    }

    SMS.send( user.phone, random );

    Auth auth = new Auth();
    auth.token = uuid;

    return objectMapper.writeValueAsString( auth );
}

So trying to do the following:

public Mono<ServerResponse> register( ServerRequest request )
{
    Mono<User> user = request.bodyToMono( User.class );

    Mono<UserDbRecord> userDbRecord = user.flatMap( u -> Mono.just( userRepository.findByPhone( u.phone ) ) );

    int random = getRandomNumber( 111111, 999999 );

    String uuid = null;

    //first, check if user already did registration from that phone

    //now what???
    if( userDbRecord != null )
    {
        logger.info( "register. User already exist with phone: " + userDbRecord.getPhone() + ", id: " + userDbRecord.getId() );

        uuid = userDbRecord.getToken();
    }
    else
    {
        uuid = UUID.randomUUID().toString();
    }

    SMS.send( user.phone, random );

    Auth auth = new Auth();
    auth.token = uuid;

    return ok().contentType( APPLICATION_JSON ).syncBody( auth );
}

What is the best way to check if userDbRecord Mono is empty and if not empty to extract the phone property from it?

Upvotes: 2

Views: 9608

Answers (1)

Oleh Dokuka
Oleh Dokuka

Reputation: 12184

Rethink the way of data-processing

In Reactive Programming Using RxJava or Project Reactor, it is really important to continue your flow from the beginning to the end.

In your case you have to replace imperative validations/checks with reactive one:

public Mono<ServerResponse> register( ServerRequest request )
{
    return request
        .bodyToMono( User.class )
        // make sure you use Reactive DataBase Access in order to 
        // get the all benefits of Non-Blocking I/O with Project Reactor
        // if you use JPA - consider Moving to R2DBC r2dbc.io
        .flatMap( user -> // <1>
            Mono.just( userRepository.findByPhone( user.phone ) ) // <2>
                .map(userDbRecord -> {
                    logger.info( "register. User already exist with phone: " + userDbRecord.getPhone() + ", id: " + userDbRecord.getId() );
                    return userDbRecord.getToken();
                })
                .switchIfEmpty(Mono.fromSupplier(() -> UUID.randomUUID().toString())) <3>
                .flatMap(uuid -> {
                    SMS.send( user.phone, random ); <4>
                    Auth auth = new Auth();
                    auth.token = uuid;
                    return ok().contentType( APPLICATION_JSON ).syncBody( auth );
                })
        );
}

The above sample shows how you can rewrite the imperative Controller's method to a reactive one. I put a couple of comments and descriptions to them below:

  1. Here I use flatMap in order to keep access to the User Entity within created closure.
  2. Make sure you use non-blocking, reactive I/O from end to end -> ignorance of this rule can lead to negating all WebFlux benefits. In case you use JPA, consider moving to R2DBC and Spring Data R2DBC which provides you with a reactive, non-blocking replacement for JPA
  3. Frequent UUID generation can lead to thread blocking -> https://stackoverflow.com/a/14533384/4891253
  4. Make sure this is non-blocking

Upvotes: 6

Related Questions