添加 json 正文到 http4s 请求

Add json body to http4s Request

本教程展示了如何创建 http4s 请求:https://http4s.org/v0.18/dsl/#testing-the-service

我想将此请求更改为 POST 方法并使用 circe 添加文字 json 正文。我尝试了以下代码:

val body = json"""{"hello":"world"}"""
val req = Request[IO](method = Method.POST, uri = Uri.uri("/"), body = body)

这给了我一个类型不匹配错误:

[error]  found   : io.circe.Json
[error]  required: org.http4s.EntityBody[cats.effect.IO]
[error]     (which expands to)  fs2.Stream[cats.effect.IO,Byte]
[error]     val entity: EntityBody[IO] = body

我理解错误,但我不知道如何将 io.circe.Json 转换为 EntityBody。我见过的大多数示例都使用 EntityEncoder,它不提供所需的类型。

如何将 io.circe.Json 转换为 EntityBody

Oleg 的 link 大部分内容都涵盖了它,但下面是您如何为自定义请求正文执行此操作:

import org.http4s.circe._

val body = json"""{"hello":"world"}"""
val req = Request[IO](method = Method.POST, uri = Uri.uri("/"))
  .withBody(body)
  .unsafeRunSync()

解释:

请求 class 上的参数 bodyEntityBody[IO] 类型,它是 Stream[IO, Byte] 的别名。不能直接给它赋值String或者Json对象,需要用withBody方法代替。

withBody 采用隐式 EntityEncoder 实例,因此您关于不想使用 EntityEncoder 的评论没有意义 - 您 如果您不想自己创建字节流,请使用一个。但是,http4s 库为许多类型预定义了一个,Json 类型的预定义在 org.http4s.circe._ 中。因此导入语句。

最后,你需要在这里调用.unsafeRunSync()来拉出一个Request对象,因为withBodyreturns一个IO[Request[IO]]。处理这个问题的更好方法当然是将结果与其他 IO 操作链接起来。

从 http4s 20.0 开始,withEntity 用新主体覆盖现有主体(默认为空)。 EntityEncoder 仍然是必需的,可以通过导入 org.http4s.circe._:

找到
import org.http4s.circe._

val body = json"""{"hello":"world"}"""

val req = Request[IO](
  method = Method.POST,
  uri = Uri.uri("/")
)
.withEntity(body)