Reputation: 31
I am wondering which is the correct or best way to map or merge several reactive service responses into one unique object.
For the example, simple traditional code like this:
public UserProfile getUserProfile(String id){
User user = userService.getUser(id);
Messages messages = messageService.getMessagesFromUser(id);
Notifications notifications = notificationService.getNotificationsForUser(id);
return new UserProfile(user, message, notifications);
}
When trying to write it more "functional like" using webflux, it looks something like this:
public Mono<UserProfile> getUserProfile(String id){
return userService.getUser(id)
.map( user -> {
return messageService.getMessagesFromUser(id)
.map(messages -> {
return notificationService.getNotificationsForUser(id)
.map(notifications -> new UserProfile(user, message, notifications))
}
}
}
I personally, don't like this kind of "map steps", because it is not a sequential transformation. I need more like parallel processing, that's really easy to implement with CompletableFuture or other multithreading framework and traditional imperative code (not functional).
How do you think you can improve this implementation? This code works fine, but I don't think it's the correct way to write it. It seems to me that it looks ugly and not very understandable.
EDIT!!! I think I've found a better approach using Mono.zip, still I think it should be improvable
@GetMapping("v1/event/validate/")
public Mono<PanoramixScoreDetailDTO> validateEvent(@RequestBody LeadEventDTO eventDTO) {
return leadService.getLead(eventDTO.getSiteId(), eventDTO.getIdContacto())
.flatMap(lead -> {
Mono<PhoneValidationDTO> phoneValidation = validationService.validatePhone(eventDTO.getSiteId(), lead.getPhone());
Mono<EmailValidationDTO> emailValidation = validationService.validateEmail(eventDTO.getSiteId(), lead.getLeadUser().getEmail());
Mono<ProcessedProfileSmartleadDTO> smartleadProfile = smartleadService.getProcessedProfile(eventDTO.getSiteId(), eventDTO.getIdUsuario());
return Mono.zip(phoneValidation, emailValidation, smartleadProfile)
.map(tuple -> panoramixScoreMapper.mapTo(lead, tuple.getT1(), tuple.getT2(), tuple.getT3(), eventDTO));
});
}
I would like to hear your opinions. Thanks!
Upvotes: 3
Views: 3387
Reputation: 943
This is working for me.
public Mono<UserProfile> getUserProfile(final String id) {
// TODO
return Mono
.zip(user, messages, notifications)
.map(tuple -> new UserProfile(tuple.getT1(), tuple.getT2(), tuple.getT3()));
}
Upvotes: 0
Reputation: 72294
Mono.zip()
is the way to go, but you can save a step by using the override that allows you to specify both your zipped publishers and your map function in one go:
@GetMapping("v1/event/validate/")
public Mono<PanoramixScoreDetailDTO> validateEvent(@RequestBody LeadEventDTO eventDTO) {
return leadService.getLead(eventDTO.getSiteId(), eventDTO.getIdContacto())
.flatMap(lead ->
Mono.zip(arr ->
panoramixScoreMapper.mapTo(lead, (PhoneValidationDTO) arr[0],
(EmailValidationDTO) arr[1],
(ProcessedProfileSmartLeadDTO) arr[2], eventDTO),
validationService.validatePhone(eventDTO.getSiteId(), lead.getPhone()),
validationService.validateEmail(eventDTO.getSiteId(), lead.getLeadUser().getEmail()),
smartleadService.getProcessedProfile(eventDTO.getSiteId(), eventDTO.getIdUsuario()))
);
}
Upvotes: 1