Scala - Futures and Ayers

this thread gave me an idea of ​​how to structure my code: Scala -way to handle conditions for understanding?

Part in question:

// First create the JSON val resultFuture: Future[Either[Failure, JsResult]] = for { userRes <- userDao.findUser(userId) user <- userRes.withFailure(UserNotFound).right authRes <- userDao.authenticate(user) auth <- authRes.withFailure(NotAuthenticated).right goodRes <- goodDao.findGood(goodId) good <- goodRes.withFailure(GoodNotFound).right checkedGood <- checkGood(user, good).right } yield renderJson(Map("success" -> true))) 

These are the lines that I do not understand:

 user <- userRes.withFailure(UserNotFound).right authRes <- userDao.authenticate(user) 

userRes.withFailure (UserNotFound) .right maps to userDao.authenticate (user) . This will lead to the creation of a new Either with the Future on the right, right?

how

 val resultFuture: Future[Either[Failure, JsResult]] 

will be of its type. I think there should be a different future instead of JsResult. Can someone explain this to me?

EDIT . Since cmbaxter and Arne Claassen have confirmed this, a new question is: How do I write this code, so it doesn't look ugly, but clean and structured?

0
source share
1 answer

I believe that the answer you got uselessly mixed Either in the mix when Future already doing an excellent job with the error message. The main thing that you lacked is a way to get the value of a parameter from Option without explicitly throwing exceptions.

I suggest you change the Failure object to the following:

 object Failures { sealed trait Failure extends Exception // Four types of possible failures here case object UserNotFound extends Failure case object NotAuthenticated extends Failure case object GoodNotFound extends Failure case object NoOwnership extends Failure // Put other errors here... // Converts options into Futures implicit class opt2future[A](opt: Option[A]) { def withFailure(f: Failure) = opt match { case None => Future.failed(f) case Some(x) => Future.successful(x) } } } 

Now you can map Future[Option[A]] to Future[A] and specify a failure condition, as a result of which the following is understood for understanding:

 def checkGood(user: User, good: Good) = if (checkOwnership(user, good)) Future.successful(good) else Future.failed(NoOwnership) val resultFuture: Future[JsResult] = for { userOpt <- userDao.findUser(userId) user <- userOpt.withFailure(UserNotFound) authOpt <- userDao.authenticate(user) auth <- authOpt.withFailure(NotAuthenticated) goodOpt <- goodRes.withFailure(GoodNotFound) checkedGood <- checkGood(user, good) } yield renderJson(Map("success" -> true)))) 

Now that you have Future[JsResult] , you can match the failed scenarios with the desired result, and the success scenario is just JsResult. I hope you use this in an asynchronous structure that expects you to feed it in the future and it has its own bad future for matching error responses (e.g. Play!).

+4
source

Source: https://habr.com/ru/post/970449/


All Articles