Reputation: 1085
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
Reputation: 12184
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:
flatMap
in order to keep access to the User
Entity within created closure.Upvotes: 6