Open FunFunFine opened 3 years ago
Hm interesting problem :)
Having a Decoder[ErrorInfo]
, you don't really know that you are able to decode a json into NotFound
- the decoder may always return NoContent
, for example.
So other than defining decoders for NotFound
etc which verify that the discriminator is present, I don't think I have a good solution.
One direction to explore, might be in jsonBody[T]
requiring an Encoder[U]
, where U <: T
, as if we need to encode a T
, a U
-encoder will work just fine. But there might be reasons why Encoder
is not covariant in the first place. This would solve the encoding part, but the decoder would still be problematic.
Another note. I can't find statusDefaultMapping
in the latest code. But it is still in the documentation.
Anyone who tries the example code will get a complier error.
@Zhen-hao This is now renamed to oneOfDefaultVariant
. Where in the docs did you encounter statusDefaultMapping
?
@Zhen-hao ah in the ADR, fixed :)
My workaround (with zio-json
):
def jsonBody2[T: JsonEncoder: JsonDecoder, U <: T: Schema]: EndpointIO.Body[String, U] = {
implicit val enc = JsonEncoder[T].narrow[U]
implicit val dec = JsonDecoder[T].asInstanceOf[JsonDecoder[U]]
// this is safe only in the case where T is a sealed trait with an auto-generated decoder for all subtypes
stringBodyUtf8AnyFormat(zioCodec[U])
}
usage (same as above):
statusMapping(StatusCode.NotFound, jsonBody2[ErrorInfo, NotFound].description("not found"))
Tapir version: 0.17.12
Scala version: 2.13.5
Prerequisites
So let's say I have the following error ADT:
And defined circe codec produces and expects the discriminator object:
Problem
I want to use
ErrorInfo
in the error output of my endpoint, so I write this code:And it does not compile, because the compiler can't find circe codec for each case of the ADT:
which is understendable actually because of
jsonBody
signature:def jsonBody[T: Encoder : Decoder: Schema]
— T here and in circe's typeclasses is invariant.I could use
import io.circe.generic.auto._
but then the output differs from what I expect: it's just plain JSON without discriminator:{ "what" : "something" }
.Workaround
For now, I am using this custom output:
and this works but feels very wrong.
Question
So what can be done to fix this behaviour? Is there a built-in way to work with that in Tapir? If there is none, can I contribute it?