Тапир Custom кодек - PullRequest
       27

Тапир Custom кодек

2 голосов
/ 16 марта 2020

Я застрял в каком-то месте, я использую scala, тапир и Circe.

sealed abstract class S1Error extends Product with Serializable
object S1Error {
  final case class SError(error: SMError) extends S1Error
}
sealed abstract class SMError(message: String)
object SMError {
  final case class SVError(message: String) extends SMError(message)
}

При ошибке тапира, я использую это

val schemaVersionError: EndpointOutput.StatusMapping[SError] = statusMappingValueMatcher(
      StatusCode.BadRequest,
      jsonBody[SError]
        .description("XXXX.")
    ) {
      case SMError(SVError(_)) => true
      case _                                  => false
    }

Теперь из-за этого структура, результат API, который я получаю, является

{
    "error": {
        "SVError": {
            "message": "XXXXG"
        }
    }
}

, где в идеале я хотел бы получить ответ, как

"message": "XXXXG"

Я не могу изменить структуру ошибки. Есть ли способ обернуть эту ошибку, используя пользовательский код c, чтобы получить требуемый результат.

1 Ответ

2 голосов
/ 16 марта 2020

Код Tapir c получен из декодера и кодировщика Circe.

То, что вы видите, является способом кодирования классов случаев по умолчанию для circe.

Circe предоставляет возможность кодировать классы случаев. как вы описали с deriveUnwrappedEncoder из circe-generi c -extras . К сожалению, он не компилируется для SMError (возможно, механизм деривации путается с вашей абстрактной иерархией классов).

Что вы можете сделать, это просто создать кодер вручную:

sealed abstract class S1Error extends Product with Serializable

object S1Error {
  final case class SError(error: SMError) extends S1Error

  implicit val encoder: Encoder[SError] = Encoder[SMError].contramap(_.error)
  // or you can use deriveUnwrappedEncoder from circe-generic-extras:
  // implicit val encoder: Encoder[SError] = deriveUnwrappedEncoder
}

//I also needed to make message a field in SMError
sealed abstract class SMError(val message: String)
object SMError {
  final case class SVError(override val message: String) extends SMError(message)

  implicit val encoder: Encoder[SMError] = Encoder.encodeJsonObject.contramap{s => JsonObject("message" -> s.message.asJson)}
}

Ответ теперь выглядит так:

{
    message": "XXXXG"
}
...