在 http4s 中发送 JSON 响应的正确方法是什么?

What is the right way to send JSON response in http4s?

不久前我从 akka-http 切换到 http4s。我想正确做的基本事情之一——JSON 处理,特别是发送 JSON 响应。

我决定将 http4s 与 ZIO 而不是 cat 一起使用,因此 http 路由如下所示:

import fs2.Stream
import org.http4s._
import org.http4s.dsl.io._
import org.http4s.implicits._
import scalaz.zio.Task
import scalaz.zio.interop.catz._
import io.circe.generic.auto._
import io.circe.syntax._

class TweetsRoutes {

  case class Tweet(author: String, tweet: String)

  val helloWorldService = HttpRoutes.of[Task] {
    case GET -> Root / "hello" / name => Task {
      Response[Task](Ok)
        .withBodyStream(Stream.emits(
          Tweet(name, "dummy tweet text").asJson.toString.getBytes
        ))
    }
  }.orNotFound

}

如您所见,JSON 序列化部分非常冗长:

.withBodyStream(Stream.emits(
  Tweet(name, "dummy tweet text").asJson.toString.getBytes
))

是否有任何其他方式在响应中发送 JSON?

是的,有:为任务定义和编码器和解码器:

implicit def circeJsonDecoder[A](
      implicit decoder: Decoder[A]
  ): EntityDecoder[Task, A] = jsonOf[Task, A]
  implicit def circeJsonEncoder[A](
      implicit encoder: Encoder[A]
  ): EntityEncoder[Task, A] = jsonEncoderOf[Task, A]

这样就不用转字节了

编辑:这里有一个完整的例子:https://github.com/mschuwalow/zio-todo-backend/blob/develop/src/main/scala/com/schuwalow/zio/todo/http/TodoService.scala

HT:@mschuwalow

对此还有更简单的解决方案。如果你想为 HTTP 响应处理 case class JSON 编码,你可以添加这些导入:

import io.circe.generic.auto._
import org.http4s.circe.CirceEntityCodec._

顺便说一句,相同的导入处理传入的 JSON 请求的解码到案例 classes 以及