guardrail-dev / guardrail-dev/guardrail
Circe `allOf` support generates uncompilable code when a variant has only discriminators
- Dominant language
- Scala
- Stars
- 541
- Forks
- 138
- PR merge metrics
- No merged PRs in 30d
Description
Consider:
```
Request:
type: object
required:
- type
properties:
type:
type: string
discriminators:
propertyName: type
FooRequest:
- $ref: "#/components/schemas/Request"
- type: object
required:
- foo
properties:
foo:
type: string
BarRequest:
- $ref: "#/components/schemas/Request"
BazRequest:
- $ref: "#/components/schemas/Request"
```
The issue here arises in part because guardrail's Circe generator doesn't include the discriminator as a field in the generated case classes. `FooRequest` is generated ok, but `BarRequest` and `BazRequest` end up as case classes with no fields, and so it tries to write encoders/decoders using `.forProduct0()`, which is not a thing.
It might seem weird to want to describe the API this way in the spec, but consider that, because discriminators are left out of the final case classes, there's no way in this scenario to determine if the request you get has `"type": "BarRequest"` or `"type": "BazRequest"` in it.
If we were to include the discriminator value as a field in the case class, then definitions for `BarRequest` and `BazRequest` would be unnecessary; _however_, then that would also not be so ergonomic, because you'd have to write code like this:
```
request match {
case FooRequest(_, foo) => // ...
case Request(`type`) if `type` == "BarRequest" => // ...
case Request(`type`) if `type` == "BazRequest" => // ...
case Request(`type`) => throw new IllegalArgumentException(s"Type ${`type`} is not valid")
}
```
... which is obviously kinda ugly. (Also I think guardrail will generate a trait for `Request` in this case, so that won't really work anyway.)
So I think the ideal way to go would be to detect if a case class instance has zero fields (or I guess could even use a case object here), and then just generate an encoder that only encodes the discriminator (with something analogous for the decoder).
Contributor guide
Assessment
This issue has not been assessed yet.