3
votes

I am new Spring Webflux. I am writing a simple api which call another api and returns response. The problem I have is my api takes diffrent type of request than the external api.I have to convert the incoming request to send to external api.I am using Mono to receive request for my api, but having trouble to convert to another object without block().

Input

Router

@Configuration
@EnableWebFlux
public class RouterConfig implements WebFluxConfigurer{

    @Bean
    public RouterFunction<ServerResponse> routes(UserHandler handler){
        
        return RouterFunctions
                .route(POST("/rest/create"),
                        handler::createUser);
    }
    
} 

Handler

@Component
public class UserHandler {

    private UserService service;

    public UserHandler(UserService service) {
    this.service = service;
    }

      
    public Mono<ServerResponse> saveUser(ServerRequest request) 
    {
    
        Mono<User> user = request.bodyToMono(User.class)
    
        /* currently I am using block to get User object */
    
         User user1 = user.block()
    
        /* convert user to person */
       
           Person p =getPersonFromUser(user);
    
       
    
        
    }

Pojos

 class User
    {
      private String name;
      private String id;
      private String email;
       private String phone;    
    
    
    }



 class Person
    {
      private String email;
      /* Combination of id and name */
      private String accountNumber;
      private String phone;
    
    }

Is there a way I can convert the Mono to Person object without blocking?

1

1 Answers

3
votes

If you're willing to have Person p processed in a Mono-Lambda, then you can try

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

    // Convert a Mono<User> to a Mono<Person>    
    .map((User user1) -> getPersonFromUser(user))

    .map((Person p) -> {
        // Code that either returns ServerResponse object or an intermediary object
    })
    // Additional code as needed

Because request.bodyToMono(User.class) returns a Mono of a User, you can call that Mono's map method. the map method takes in a lambda of type Function which takes in a parameter of one type and returns an object of a different type.

The first map call made:

.map((User user1) -> getPersonFromUser(user))

is given a Lambda that takes in a Function that converts a User to a Person, hence I jumped from having a "Mono for User" to a "Mono for Person".

I don't know if there is a way to get a ServerResponse directly from Person but in the second map call, you can write the function to return a ServerResponse (in which case you have a "Mono of a ServerResponse" and you're basically done) or return another intermediary object. If you do the latter, you'll likely need additional mapping calls.

Note: If within your Lambda, you get a Mono, you'll want to use the flatMap method, i.e. if getPersonFromUser(user) returns a Mono of a Person instead of a Person, then instead of

.map((User user1) -> getPersonFromUser(user))

you would use

.flatMap((User user1) -> getPersonFromUser(user))

You can checkout this StackOverFlow Question if you're interested in map vs flatmap