Scalaz extensions
FutureEither
FutureEither
is a specialised version of scalaz.EitherT[Future, A, B]
which allows simple composition of
Future[A \/ B]
operations.
Usage
Include the dependency from maven central: com.beamly:beamly-core-scalaz
import scala.concurrent.Future
import beamly.core.scalaz.future.{FutureEither, \?/}
import com.zeebox.core.http.common.HttpStatus.{NotFound, Ok}
import com.zeebox.core.http.server.http.HttpResponse
case class UserNotFound(userId: String)
class Example {
def findFriends(userId: UserId): UserNotFound \?/ Seq[User] = ???
def handleUserNotFound: UserNotFound => HttpResponse[Nothing] = {
userNotFoundError => HttpResponse.failure(NotFound, s"User $userId not found")
}
def friendsResponse(userId: UserId): Future[HttpResponse[Seq[User]]] = {
val response: FutureEither[HttpResponse[Nothing], HttpResponse[Seq[User]]] =
for {
friends <- findFriends(userId) leftMap handleUserNotFound
} yield HttpResponse(Ok, data = Some(friends))
response.union
}
}
The steps above when calling friendsResponse
are:
- call
findFriends
which returns either a user not found error or a list of friends - the call to
leftMap
maps the left-hand result (ie:UserNotFound
) to a 404HttpResponse
- the yield returns the right-hand result which is the list of your friends, but wrapped in a 200
HttpResponse
- the entire for-comprehension thus returns
FutureEither[HttpResponse[Nothing], HttpResponse[Seq[User]]]
- the
union
method flattens theFutureEither[HttpResponse[Nothing], HttpResponse[Seq[User]]]
to aFuture[HttpResponse[Seq[User]]]
Future
to a FutureEither
Converting a regular def findUser(userId: UserId): Future[Option[User]]
findUser.toEither.leftMap {
case ex: UserNotFoundException =>
UserNotFound(userId)
}
findUser.toEither
returns FutureEither[Throwable, Option[User]]
and the leftMap
call simply converts Throwable
to UserNotFound
.