Reputation: 3495
I'm relatively new to webflux and i want to find solution to avoid nested flatMap when there are conditionals:
I have 3 simple entities:
Item, Brand, Category.
Item basically contains: brandId and categoryId
public Mono<Item> patch(String itemId, PatchSpecs specs) {
return itemRepository.findById(itemId)
.switchIfEmpty(Mono.error(..)))
.flatMap(item -> {
final String brandId = specs.getBrandId();
if (brandId != null) {
return brandService.getById(brandId)
.switchIfEmpty(Mono.error(..)))
.flatMap(brand -> {
final String categoryId = specs.getCategoryId();
if (categoryId != null) {
return categoryService.getById(categoryId)... -> return updateAndSave(..)
}
return updateAndSave(specs, item, brand, null);
});
}
else {
final String categoryId = specs.getCategoryId();
if (categoryId != null) {
return categoryService.getById(categoryId)... -> return updateAndSave(..)
}
return updateAndSave(specs, item, null, null);
}
});
}
How do I prevent this branching conditional flatMaps mess? I cannot imagine if i have another entity inside Item. There will be more nested flatMaps?
Upvotes: 3
Views: 7259
Reputation: 9937
If I understand your code well category and brand are optional attributes of the item. In this case I'd recommend the following:
public Mono<Item> patch(String itemId, PatchSpecs specs)
{
return itemRepository.findById(itemId)
.switchIfEmpty(Mono.error(new RuntimeException("Can not find item.")))
.flatMap(item -> updateAndSave(specs, item));
}
private Mono<? extends Item> updateAndSave(PatchSpecs specs, Item item)
{
Mono<Optional<Brand>> brand = getBrand(specs.getBrandId());
Mono<Optional<Category>> category = getCategory(specs.getCategoryId());
return Mono.zip(Mono.just(item), brand, category)
.flatMap(tuple -> updateAndSave(specs, tuple));
}
private Mono<Optional<Brand>> getBrand(String inputBrandId)
{
return Mono.justOrEmpty(inputBrandId)
.flatMap(brandId -> brandService.getById(brandId)
.switchIfEmpty(Mono.error(new RuntimeException("Can not find brand."))))
.map(Optional::of)
.defaultIfEmpty(Optional.empty());
}
private Mono<Optional<Category>> getCategory(String inputCategoryId)
{
return Mono.justOrEmpty(inputCategoryId)
.flatMap(brandId -> categoryService.getById(brandId)
.switchIfEmpty(Mono.error(new RuntimeException("Can not find brand."))))
.map(Optional::of)
.defaultIfEmpty(Optional.empty());
}
private Mono<Item> updateAndSave(PatchSpecs specs, Tuple3<Item, Optional<Brand>, Optional<Category>> tuple)
{
Item item = tuple.getT1();
Brand brand = tuple.getT2().orElse(null);
Category category = tuple.getT3().orElse(null);
// TODO do update and save here
return null;
}
It will be more extensible this way and no need for duplication and nested conditionals. Please, verify it works as you expect.
Upvotes: 5