如何映射Future的失败投影

时间:2018-04-17 19:20:26

标签: scala playframework-2.6 silhouette

在以下代码中,该函数应返回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*/

      }
    }
  }

2 个答案:

答案 0 :(得分:3)

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

   futureValue.map{value => //RESULT
}

在Future中处理错误,建议使用像地图一样的恢复:

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

如果结果已经在map或recover块中,则不需要将结果包装在Future中。由于地图之外的最终结果和Future的恢复将是Future [Result]。因此,如果你换另一个未来,它将成为未来[未来[结果]]。

答案 1 :(得分:0)

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

目前尚不清楚您使用的是哪个库,但在大多数情况下,无需明确调用data。每个体面的http库(例如akka-http)都将失败的未来视为InternalServerError。