Http4s解码器如何自定义无效字段的错误信息

问题描述

我有以下代码:

 case req @ POST -> Root =>
        req
          .decode[UserCreateRequest] { decodedRequest =>

我的堆栈是 http4s + zio。

我为这个案例类添加了自定义解码器,我有一行:

email <- Either.cond(StringValidator.isValidEmail(emailStr),Email(emailStr),DecodingFailure("email",c.history))

发布无效的 json,使用无效的电子邮件返回我:

HTTP/1.1 422 不可处理实体内容类型:文本/纯文本; charset=UTF-8 日期:2021 年 1 月 19 日星期二 16:46:27 GMT 内容长度:29

请求正文无效。

响应代码:422(不可处理的实体);时间:681ms;内容 长度:29 字节

我想自定义。在 http4s 代码中,我看到 InvalidMessageBodyFailure。 但是我在文档中找不到任何有关如何自定义此响应的信息。

有人可能已经尝试过吗?

谢谢

编辑:

示例 UserCreateRequest:

final case class UserCreateRequest(
    email: Email
  )

final case class Email(value: String) extends AnyVal

json 请求:

{
 "email": "myemail[at]gmail.com"
}

这可以使用这样的代码来实现:

(for {
          decodedJson <- req.asJson.mapError { decodingError =>
            HttpDecodingError(cause = decodingError.getMessage)
          }
          decodedRequest <- Task.fromEither(decodedJson.as[UserCreateRequest]).mapError { decodingError =>
            HttpDecodingError(cause = decodingError.getMessage)
          }
          response <- UserService
            .createNewUser(
              decodedRequest.email
            )
            .bimap(
              error => HttpGenericError(msg = error.msg,cause = error.cause.toString),u => UserResponse(u.email.value)
            )
        } yield response).foldM((error: HttpError) => BadRequest(error),u => Ok(u))

但我想知道它是否可以通过一些 http4s 核心功能来简化,这些功能已经完成但没有记录:)

解决方法

您可以直接从 API 返回 Status。也就是说,您可以构造一个 UnprocessableEntity 实例并使用 withXXX 方法来更改响应。

假设一些结构:

final case class UserCreateRequest(isValid: Boolean)

你可以这样做:

case req @ POST -> Root / "foo" =>
  for {
    req <- req.decodeJson[UserCreateRequest]
    resp <- if (req.isValid) Ok()
            else UnprocessableEntity().map(_.withEntity(???).withAttribute(???))
  } yield resp

相关问答

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