2016-03-01 43 views
1

我有一个游戏框架作用,这需要完成顺序3件事情实用的风格: -这种多任务操作

  1. 得到两个参数(A,B)的要求
  2. 如果两个PARAMS存在,那么用A来从缓存中获取
  3. 如果条目缓存中存在的条目,然后

我有什么到目前为止调用Web服务与B: -

// 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)) 
    } 

} 

我明显地忽略了一些对我的问题并不重要的简洁的细节。

我的问题是(作为斯卡拉新手)什么将是一个很好的功能方式来完成此操作。如果参数不存在,那么我不想执行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)) 
    } 
} 

我非常感谢任何有关人们如何更优雅地接近我的上述解决方案的意见。

回答

2

正如您已经注意到的,有很多方法可以依赖Future s和Option s来完成这件事,而这确实是一个品味问题。如果在给定情况下更清楚地传达您的观点,我认为在使用if表达式时不存在任何内在错误。也就是说你可以:

使用表达式与.getOrElse确保你的参数都满足(尽管嵌套for有时看起来不太好)。稍微(和不必要的)你的逻辑golfed重写可能是这样的:

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) 
     } 
    } 
) 
} 

几个好职位来读取这种事情是:

+0

迈克,非常感谢您抽出宝贵的细节做出响应的时间。几个很好的选择让我去工作。 ;) – JamieP