斯卡拉/Play : how to write JSON result from async db call to http Ok

标签 scala asynchronous playframework couchbase

问:调用 Ok() 从异步数据库调用发送 http 响应的正确位置在哪里?

我已经学习了非常基本的 Scala Play 框架教程 play-scala-starter-example作为起点,添加一些使用 ReactiveCouchbase 的附加基本 Controller /服务类用于数据库访问。

申请成功:

  • 连接到 Couchbase
  • 在 Couchbase 中存储 JSON 文档
  • 从 Couchbase 检索存储的 JSON 文档
  • 将 JSON 的内容记录到控制台

我是 Scala/Play 新手,无法找出在异步数据库调用完成时使用 Ok() 成功将 JSON 写回 http 响应的正确方法。

Controller 类内部有以下函数:

  def storeAndRead() = Action {
    testBucket 
    .insert[JsValue]("key1", Json.obj("message" -> "Hello World", "type" -> "doc"))

    val res = testBucket
      .get("key1")
      .map(i => Json.toJson(i.get))
      .map(j => Ok(j))  // PROBLEM LINE

}

查看“//PROBLEM LINE”,在映射内调用 Ok() 会导致编译错误:

CouchbaseController.scala:30:19: Cannot write an instance of Unit to HTTP response. Try to define a Writeable[Unit]

稍后调用 Ok(),失败并出现不同的编译错误:

  def storeAndRead() = Action {
    testBucket
      .insert[JsValue]("key1", Json.obj("message" -> "Hello World", "type" -> "doc"))

    val res = testBucket
      .get("key1")
      .map(i => Json.toJson(i.get))

    Ok(res)
  }

编译错误:

CouchbaseController.scala:35:7: Cannot write an instance of scala.concurrent.Future[play.api.libs.json.JsValue] to HTTP response. Try to define a Writeable[scala.concurrent.Future[play.api.libs.json.JsValue]]

在第二种情况下,我认为问题在于调用 Ok() 时 Future 可能尚未完成?

最后,我尝试将对 Ok() 的调用放在 onSuccess() 函数中,以确保在异步函数完成后调用它:

  def storeAndRead() = Action {
    testBucket 
      .insert[JsValue]("key1", Json.obj("message" -> "Hello World", "type" -> "doc"))

    val res = testBucket
      .get("key1")
      .map(i => Json.toJson(i.get))
      .onSuccess {
        //case doc => Console.println("completed: " + doc)
        case doc => Ok(doc)
      }

  }

再次...编译错误:

CouchbaseController.scala:22:24: overloaded method value apply with alternatives:
[error]   (block: => play.api.mvc.Result)play.api.mvc.Action[play.api.mvc.AnyContent] <and>
[error]   (block: play.api.mvc.Request[play.api.mvc.AnyContent] => play.api.mvc.Result)play.api.mvc.Action[play.api.mvc.AnyContent] <and>
[error]   [A](bodyParser: play.api.mvc.BodyParser[A])play.api.mvc.ActionBuilder[play.api.mvc.Request,A]
[error]  cannot be applied to (Unit)
[error]   def storeAndRead() = Action {

问题:

我显然错过了一些相当基本的东西:

这种基本场景下应该在哪里调用Ok()呢?我认为异步数据库请求完成时需要作为回调结果调用它?

对于 Scala/Play 以异步方式构建此结构的正确且适当的方法是什么?

最佳答案

使用 Action.async 处理 future 结果

Play 知道如何处理 Future(异步调用)。您必须使用 Action.async

例如:

def myAction = Action.async {
    // ...
    myFuture.map(resp => Ok(Json.toJson(resp)))
}

就您而言:

def storeAndRead() = Action.async {
    // by the way, the expression behind probably returns a future, you should handle it
    testBucket 
        .insert[JsValue]("key1", Json.obj("message" -> "Hello World", "type" -> "doc")) 


    testBucket
        .get("key1")
        .map(i => Json.toJson(i.get))
        .map(j => Ok(j))  

}

您必须返回一个Result(或一个Future[Result])

您收到错误CouchbaseController.scala:30:19:无法将 Unit 实例写入 HTTP 响应。尝试定义一个 Writeable[Unit] 因为您不返回任何内容。这里需要一个 Result

处理 future 链

此外,您应该处理多个 Future 的调用。如果不这样做,即使客户端收到了 http 响应,您也会收到静默错误。

例如:

def storeAndRead() = Action.async {
    for {
        _     <- testBucket.insert[JsValue]("key1", Json.obj("message" -> "Hello World", "type" -> "doc")) 
        value <- testBucket.get("key1")
    } yield Ok(Json.toJson(value))

}

关于斯卡拉/Play : how to write JSON result from async db call to http Ok,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48583515/

相关文章:

algorithm - 简单循环太慢

scala - 在 Scala 中表示 readline 循环的最佳方式?

xml - Scala XML 构建 : Adding children to existing Nodes

c# - 在 async/await 中正确处理 HttpClient 异常

javascript - Node.js - 迭代运行带有回调的函数

scala - 如何使用 Reads 对 JsValue 进行模式匹配

postgresql - 如何插入UUID的值?

scala - SublimeText 2 和 scala.sublime-build 文件

javascript - ReactJS 中的 this.state 和 this.setstate 有什么区别?

java - Play 2.4/Ebean/JPA/hibernate-entitymanager 的正确配置是什么?