Search code examples
scalascala-catseither

Scala Cats EitherT and foreach


I am trying to achieve something like the following code

def getUsers: EitherT[Future, String, Response] = {
  for {
    users <- EitherT(userRepository.findAll) // this method would retrieve a Future[Either[String, Seq[User]]]
    user <- users
    friends <- EitherT(userRepository.findFriends(user.id))
  } yield new Response(user, friends)
}

I understand that this is not possible, because EitherT does not manage foreach.

case class User(id: Long, name: String, email: String)

case class Response(user: User, friends: Seq[User])

Which would be a good way to solve this?


Solution

  • Since you are finding all users, you will have multiple users with their respective friends, so I modified your return value to return a List of Responses instead. Then perhaps you want to do something like this:

    import cats.data.EitherT
    import cats.syntax.traverse._
    import cats.instances.list._
    import cats.instances.future._
    import scala.concurrent.Future
    
    def getUsers: EitherT[Future, String, List[Response]] = {
      EitherT(userRepository.findAll).flatMap { users =>
        users.toList.traverse(user => EitherT(userRepository.findFriends(user.id)).map(Response(user, _)))
      }
    }
    

    Make sure you have an implicit ExecutionContext in scope or import scala.concurrent.ExecutionContext.Implicits.global.