Декодер Http4s, как настроить сообщение об ошибке для недопустимых полей
У меня есть следующий код, например:
case req @ POST -> Root =>
req
.decode[UserCreateRequest] { decodedRequest =>
мой стек http4s + zio.
Я добавил пользовательский декодер для этого класса case, где у меня есть строка:
email <- Either.cond(StringValidator.isValidEmail(emailStr), Email(emailStr), DecodingFailure("email", c.history))
Публикация недопустимого json с неверным адресом электронной почты возвращает меня:
HTTP/1.1 422 Unprocessable Entity Content-Type: text/plain;charset=UTF-8 Дата: вторник, 19 января 2021 г., 16:46:27 GMT Content-Length: 29
Тело запроса недействительно.
Код ответа: 422 (необрабатываемый объект); Время: 681 мс; Длина содержимого: 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, которые уже сделаны, но не задокументированы :)
1 ответ
Вы можете напрямую вернуть
Status
из вашего API. т.е. вы могли бы построить
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