【问题标题】:how to map the failed projection of a Future如何映射未来的失败投影
【发布时间】:2018-09-27 21:11:42
【问题描述】:

在以下代码中,该函数应返回Future[Result] 的实例,但我无法这样做。代码查询数据库,数据库返回Future[User]。我认为我能够正确映射未来的成功部分,但不能正确映射失败部分。请看函数末尾的注释。

def addUser = silhouette.UserAwareAction.async{ implicit request => {
    val body: AnyContent = request.body
    val jsonBody: Option[JsValue] = body.asJson

//check for message body. It should be json
    jsonBody match {
      case Some(json) => { //got json in message body.
        val readableString: String = Json.prettyPrint(json)
        println(s"received Json ${readableString}")
        val userProfile: Option[UserProfile] = json.asOpt[UserProfile] //check if json conforms with UserProfile structure
        userProfile match {
          case Some(profile) => { //json conforms to UserProfile.
            println(s"received profile ${profile}")

            val loginInfo = LoginInfo(CredentialsProvider.ID, profile.externalProfileDetails.email)
            println(s"checking if the user with the following details exists ${loginInfo}")

            val userFuture: Future[Option[User]] = userRepo.find(loginInfo) // userFuture will eventually contain the result of database query i.e Some(user) or None
            userFuture.map { user:Option[User] => { //Future successful
                case Some(user) => { //duplicate user
                  println("duplicate user" + user)
                  Future  { Ok(Json.toJson(JsonResultError("duplicate user")))   }
                }
                case None => { //unique user
                    Future { Ok(Json.toJson(JsonResultSuccess("Not duplicate user"))) }
                }
              }
            }

/***This is the part I am unable to code. I suppose the addUser method expect that the last statement (its return value) is Future{....} but it seems that they way I have coded it, it is not the case. If I remove this code and just type Future { Ok(Json.toJson(JsonResultSuccess("Internal Server Error"))) } then code compiles. But that logic is not correct because then this message will be sent all the time, not when the future fails!***/
            val userFailedFuture:Future[Throwable] = userFuture.failed
            userFailedFuture.map {x=> Future { Ok(Json.toJson(JsonResultSuccess("Internal Server Error"))) }}

          }

            //Json doesn't conform to UserProfile
          case None => Future {  Ok(Json.toJson(JsonResultError("Invalid profile")))  } /*TODOM - Standardise error messages. Use as constants*/
        }
      }
        //message body is not json. Error.
      case None => Future {  Ok(Json.toJson(JsonResultError("Invalid Body Type. Need Json"))) }/*TODOM - Standardise error messages. Use as constants*/

      }
    }
  }

【问题讨论】:

    标签: scala playframework-2.6 silhouette


    【解决方案1】:

    您不必在将来包装您的结果,因为您已经从未来值进行评估,这很简单:

       futureValue.map{value => //RESULT
    }
    

    在Future中处理错误,建议使用recover with map,如:

        futureValue.map{value => //RESULT
    }.recover{case ex: Exception => //RESULT
    }
    

    如果结果已经在地图或恢复块中,则无需将结果包装在 Future 中。由于地图外的最终结果和 Future 的恢复将是 Future[Result]。因此,如果您包装另一个 Future,它将成为 Future[Future[Result]]。

    【讨论】:

    • 谢谢。所以我在map.recover 中删除了Future。我现在收到以下错误Error:(96, 59) missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5) Expected type was: play.api.mvc.Result userFuture.map { (userOption:Option[User]) => {
    • 就是这样。这是一个使用Silhouette 安全库的Playframework 应用程序。据我所知,map 正在返回Ok,它的类型为Result。但我不明白为什么编译器会抱怨。
    • 得到你的错误,你需要改变你的future.map中的代码块。更改 [userFuture.map { (userOption:Option[User]) => {] TO -> [userFuture.map{ case Some(user) => //work;案例无 => }]
    • 工作。 .recover now 也是如此。谢谢。你是个天才!虽然我不明白为什么它有效?其实看Scala文档,map的例子是val g = f map { x: String => x + " is now!" }。那么为什么我必须删除userOption:Option[User]
    • 上述错误是,您在声明变量后直接尝试使用匹配大小写(即,您可以像我上面那样做,或者如果您想遵循您的模式,那么您将不得不这样做-> future.map{value:Option[User] => value match { case Some(user) => case None => //}})
    【解决方案2】:

    同意@geek94 的回答。 一处修正:

    不清楚您使用的是什么库,但在大多数情况下,无需显式调用future.recover。每个像样的 http 库(例如 akka-http)都将失败的未来视为 InternalServerError。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-04
      • 2017-05-08
      • 1970-01-01
      • 2014-12-19
      • 1970-01-01
      • 2012-04-15
      • 2017-12-21
      相关资源
      最近更新 更多