尝试解析Future响应时有什么问题?

时间:2016-06-25 08:39:29

标签: scala http playframework response future

我有一个函数,它将通过ajax请求获取令牌。当令牌有效时,它将返回一个目录列表的响应。

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => checkToken(form.token).map(token => {
      val directories = Directories.all.map(directory => {
        Json.toJson(directory)
      })
      Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
    })
  )
}

当我运行上面的代码时它会显示[As ^符号表示发现错误的位置]

No Json serializer found for type scala.concurrent.Future[play.api.libs.json.JsValue]. Try to implement an implicit Writes or Format for this type.
Ok(Json.obj("status" -> {if (token.get.id.getOrElse(0) >= 1) true else false}, "message" -> {if (token.get.id.getOrElse(0) >= 1) Json.toJson(directories) else "Invalid token"}))
                                                                                                                                            ^

1 个答案:

答案 0 :(得分:5)

这是我想出来的

def all = Action.async(parse.json) {
  implicit request => tokenForm.bind(request.body).fold(
    formWithErrors => Future.successful(BadRequest(formWithErrors.toString)),
    form => for {
      (token, directories) <- checkToken(form.token) zip Directories.all
    } yield {
      val isTokenValid = token.isDefined
      val responseBody = Json.obj(
        "status" -> isTokenValid, 
        "message" -> {
          if (isTokenValid)
            Json.toJson(directories)
          else
            "Invalid token"
        }
      )
      Ok(responseBody)
    }
  )
}

asuming checkTokenDirectories.all返回Future

您的功能需要返回Future[Result]。折叠时,第一个分支是正确的

formWithErrors => Future.successful(BadRequest(formWithErrors.toString))

然而,在第二个分支中,您似乎通过调用Directories.all启动了一个新的Future,并且您想序列化它并以json的形式返回。 Future[JsValue]没有序列化器,因为这没有意义,它必须阻塞才能获得结果。您需要以某种方式获得checkToken(form.token)Directories.all的值。

你可以像我上面那样做,或者像这样:

form => {
  val futureToken = checkToken(form.token)
  val futureDirectories = Directories.all

  for {
    token <- futureToken
    directories <- futureDirectories
  } yield {
     // same code as above
  }
}

请注意,如果您要内联futureTokenfutureDirectories,则会以串行方式执行。

另请注意,您要将目录列表转换为json两次。

来到这里

val directories = Directories.all.map(directory => {
  Json.toJson(directory)
})

假设Directories.all返回Future[List[Directory]],那么当您使用map时,您传递的函数将在List[Directory]上运行,因此该变量应命名为directories而不是directory {1}}。它可以正常工作,轻松转换任何可转换为json的列表,无需手动执行。

你第二次在这里做了

Json.toJson(directories)