如何在Finch中绑定请求体

7

以下是将请求参数绑定到路由器的代码。

val testReader: Endpoint[Test] = Endpoint.derive[Test].fromParams
val test: Endpoint[String] = post("test" ? testReader) { t : Test => {
    Created("OK")
  }}

我正在使用fromParams方法。这个方法可以以非常酷的方式绑定请求参数。然而,我不知道在finch中有哪些类似的方法可以绑定请求体
提前致谢。
1个回答

9
为了提供一个完整的工作示例,我会假设有一个类似于这样的case class:
```scala case class Person(name: String, age: Int) ```
case class Test(foo: Int, bar: String)

还有一些类似这样的请求:

import com.twitter.finagle.http.{ Method, Request, RequestBuilder }
import com.twitter.io.{ Buf, Reader }

val queryParamPost = Request(Method.Post, "/test?foo=1&bar=whatever")

val testJsonBuf = Buf.Utf8("""{ "foo": 1, "bar": "whatever" }""")

val bodyPost = RequestBuilder().url("http://localhost:8080/test").buildPost(testJsonBuf)

现在当您编写以下内容时...
import io.finch._

val testParams: Endpoint[Test] = Endpoint.derive[Test].fromParams
val test: Endpoint[Test] = post("test" ? testParams) { test: Test =>
  Created(test)
}

现在的情况是,Finch正在使用通用派生(由Shapeless驱动)来确定(在编译时)如何将查询参数解析为Test。然后您可以像这样测试端点:

import io.finch.circe._
import io.circe.generic.auto._

test.toService.apply(queryParamPost).onSuccess { response =>
  println(s"$response: ${ response.contentString }")
}

这将打印出:

Response("HTTP/1.1 Status(201)"): {"foo":1,"bar":"whatever"}

这里我使用了Circe的通用派生(generic derivation)来自动将“created”Test编码为JSON格式并作为响应返回。

您还可以使用Circe来派生请求体的读取器:

val testBody: Endpoint[Test] = body.as[Test]
val test2: Endpoint[Test] = post("test" :: testBody) { test: Test =>
  Created(test)
}

这与上面的test几乎完全相同,但我们使用body来获取一个Endpoint[String],该端点将读取请求正文,然后使用as指定我们希望将内容解析为JSON并解码为Test值。我们可以像这样测试这个新版本:

test2.toService.apply(bodyPost).onSuccess { response =>
  println(s"$response: ${ response.contentString }")
}

我们又会得到预期的答案。

一般来说,当你想要读取请求中某种类型的信息时,你会使用Finch提供的基本Endpoint之一(请参考文档获取更完整的列表),然后在Endpoint上使用asmap等方法,将其转换成所需的形状。


我没有意识到 /、? 和 :: 实际上在做同样的事情 :) - Xiaohe Dong
@Travis Brown,您能否编辑您的答案并添加一个使用自定义解码器的简短示例?在我的用例中,Test具有类型为scalaz.Maybe的字段。将其作为Option可以工作,但是如何使其与Maybe一起工作(出于几个原因,我更喜欢Maybe而不是Option)?我一直收到“尝试在失败的光标上解码值”的错误信息。 - slouc
@slouc 那可能值得新开一个问题(我很乐意回答)。我可能会为scalaz.Maybe[A: Decoder]定义一个单独的通用实例,但需要更多细节。 - Travis Brown
@Travis Brown 是的,我想也许应该开一个新问题,但我有点懒。无论如何,我已经在此期间解决了它。我发布了问题并自己回答了;不确定SO管理员是否认为这样做可以还是不可以,但如果可以为其他人保持,则让我们继续。请随意从您的角度添加一些内容:http://stackoverflow.com/questions/42209195/circe-decoder-for-scalaz-maybe/42209211#42209211 - slouc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接