Let's look at the solution space:
Success(Right(Some(user))) => Everythig OK, got an user Success(Right(None)) => Everything OK, no user Success(Left(AppError)) => Something went wrong at app level Failure(Exception) => Something went wrong
It looks very expressive, but everything becomes terribly fast when you try to create such a nested structure using other calls (see Converting the lock code to use scala futures ) for an example of compiling Future[Option[T]] )
So, following the principle of least power , we ask ourselves: are there less complex alternatives that preserve semantics? It can be argued that Future[User] may be sufficient if we take advantage of the full potential of exclusion (and the hierarchy of exceptions).
Check:
Everythig OK, got an user => Success(user) Everything OK, no user => Failure(UserNotFoundException) (Application level exception) Something went wrong at app level => Failure(AppException) (Application level exception) Something went wrong => Failure(Exception) (System-level exception)
The only limitation of this approach is that API users will need to be aware of exceptions that are not self-documenting in the interface. The surface is that having Future based APIs will allow expressive monadic compositions with other Future -based APIs.
maasg
source share