我有一个Play框架Action需要按顺序完成3件事: -
到目前为止我所拥有的: -
// async since we are calling Async APIs like WS
def myAction = Action.async { implicit request =>
val A = requestParam(request, "a") // Option[String]
val B = requestParam(request, "b")
val futureResponse = for {
token <- getFromCache(A) recoverWith {
case e: Exception => Future.failed(new Exception("Some issue with param or cache", e))
}
wsResponse <- webServiceCall(B) recoverWith {
case e: Exception => Future.failed(new Exception("Some issue with web service call", e))
}
} yield Ok(wsResponse.body)
futureResponse recover {
case e: Exception => Ok(failureBody(e.getMessage))
}
}
我显然为了简洁而遗漏了一些对我的问题不重要的细节。
我的问题是(作为Scala新手)完成此操作的一个很好的功能方法。如果params不存在,那么我不想执行for
理解,但返回包含错误消息的Future[Result]
。目前,我能想到这样做的唯一方法是使用if
测试如下,但我不禁怀疑可能有更纯粹的方法来实现这一目标。
val A = requestParam(request, "a") // Option[String]
val B = requestParam(request, "b")
if(A.isEmpty || B.isEmpty) {
Future { Ok("Params missing") }
} else {
val futureResponse = for {
token <- getFromCache(A) recoverWith {
case e: Exception => Future.failed(new Exception("Some issue with param or cache", e))
}
wsResponse <- webServiceCall(B) recoverWith {
case e: Exception => Future.failed(new Exception("Some issue with web service call", e))
}
} yield Ok(wsResponse.body)
futureResponse recover {
case e: Exception => Ok(failureBody(e.getMessage))
}
}
我非常感谢有关人们如何更优雅地处理我的上述解决方案的任何意见。
答案 0 :(得分:2)
正如您已经注意到的那样,有很多方法可以使用依赖Future
和Option
来做事,这真的是一种品味问题。如果在特定情况下更清楚地传达您的观点,我不会认为使用if
表达式存在任何内在错误。那说你可以:
将for
表达式与.getOrElse
一起使用,以确保您的参数都满意(尽管嵌套for
有时看起来不太好看)。稍微(并且不必要地)高尔夫重写您的逻辑可能如下所示:
import scala.concurrent.Future.{successful => immediate}
def getFromCache(key: String, data: String): Future[String] = ???
def webServiceCall(key: String): Future[WSResponse] = ???
def myAction = Action.async { implicit request =>
(for {
a <- request.getQueryString("a")
b <- request.getQueryString("b")
} yield (for {
cachedData <- getFromCache(a)
r <- webServiceCall(b, cachedData)
} yield Ok(r.body)) recover {
case e => InternalServerError(e.getMessage)
}) getOrElse {
immediate(BadRequest("params missing"))
}
}
您还可以使用Form
选项来确保多个参数存在且有效,因此您可能会得到以下内容(再次稍微压缩,根据需要展开) ):
import play.api.data.Forms._
import play.api.data.Form
val form = Form(tuple("a" -> nonEmptyText, "b" -> nonEmptyText))
def myAction2 = Action.async { implicit request =>
form.bindFromRequest.fold(
err => immediate(BadRequest("missing params")), { case (a, b) =>
getFromCache(a).flatMap { cachedData =>
webServiceCall(b, cachedData).map(r => Ok(r.body))
} recover {
case e => InternalServerError(e.getMessage)
}
}
)
}
要阅读这类事情的几篇好帖子是: