Http4s circe 无法解码儿童

问题描述

我有如下错误模型:

sealed trait HttpError {
    val msg: String
    val cause: String
  }

  final case class HttpDecodingError(cause: String) extends HttpError {
    override val msg: String = "Decoding error"
  }

  final case class HttpInternalServerError(msg: String,cause: String) extends HttpError
  case object HttpUnauthorizedError extends HttpError {
    override val msg: String = "Invalid credentials"
    override val cause: String = ""
  }
  final case class HttpBadRequestError(msg: String,cause: String) extends HttpError

在我的路线中,我基于此模型生成 http 错误类型,即:

.foldM(
          {
            case error: HttpDecodingError       => BadRequest(error.asInstanceOf[HttpError])
            case error: HttpInternalServerError => InternalServerError(error.asInstanceOf[HttpError])
            case HttpUnauthorizedError          => Unauthorized(withChallenge("Invalid credentials"))
            case error: HttpBadRequestError     => BadRequest(error.asInstanceOf[HttpError])
          },Ok(_)
        )

但问题是我需要添加这个 asInstanceOf,否则 circe 看不到编码器。 我的编码器看起来像:

implicit val encodeHttpError: Encoder[HttpError] = (error: HttpError) =>
    Json.obj(("msg",Json.fromString(error.msg)),("cause",Json.fromString(error.cause)))

有没有办法避免在那里做 asInstanceOf?

解决方法

您不能将编码器用于 HttpError 的子类,因为 Encoder 是不变的(如果它是协变的,它将起作用)。

您可以使用的一种解决方案是使用参数化的 def 而不是 val 来定义编码器:

implicit def encodeHttpError[E <: HttpError]: Encoder[E] = (error: E) =>
  Json.obj(
    ("msg",Json.fromString(error.msg)),("cause",Json.fromString(error.cause))
  )

这样,您将拥有 HttpErrorHttpError 的所有子类型的编码器实例。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...