So, I'm trying to work with Webflux and I've got a scenario "check if an object exists; if so, do stuff, else - indicate error".
That can be written in reactor as:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
return id.
flatMap(repository::exists). //repository.exists returns Mono<Boolean>
flatMap(e -> e ? e : Mono.error(new DoesntExistException())).
then(
//can be replaced with just(someBusinessLogic())
Mono.fromCallable(this::someBusinessLogic)
);
}
or as:
public Mono<Void> handleObjectWithSomeId(Mono<IdType> id){
return id.
flatMap(repository::exists). //repository.exists returns Mono<Boolean>
flatMap(e -> e ? e : Mono.error(new DoesntExistException())).
map(e -> this.someBusinessLogic()));
}
Let's assume that return type of someBusinessLogic
cannot be changed and it has to be simple void
, not Mono<Void>
.
In both cases if the object won't exist, appropriate Mono.error(...)
will be produced.
While I understand that then
and flatMap
have different semantics, effectively I get the same result. Even though in second case I'm using flatMap
against its meaning, I get to skip flatMap
and fromCallable
in favor of simple map
with ignored argument (that seems more readable). My point is, both apporaches have advantages and disadvantages when it comes to readability and code quality.
So, here's a summary:
Using then
- pros
- is semantically correct
- cons
- in many cases (like above) requires wrapping in ad-hoc Mono/Flux
Using flatMap
- pros
- simplifies continued "happy scenario" code
- cons
- is semantically incorrect
What are other pros/cons of both approaches? What should I take under consideration when choosing an operator?
I've found this reactor issue that states that there is not real difference in speed.