[scala-http4s-server] Use the JSON name for the discriminator and fail decoding on unknown values

Merged
BA
2d ago
+138-4

This fixes two problems with the discriminator codecs in scala-http4s-server/types.mustache. Both branches are affected: with and without discriminator mapping.

1. The JSON key is the Scala identifier instead of the property name. The template uses propertyName. That's the Scala identifier, which is backtick-escaped for reserved words and then HTML-escaped by Mustache. With a discriminator on type, the encoder writes the key `type` and the decoder looks it up with cursor.downField("`type`"), so the polymorphic decoders never match a spec-conformant body. The template now uses propertyBaseName. #23853 made the same change in the scala-http4s client template.

2. An unknown discriminator value throws a MatchError. The flatMap over the discriminator value has no default case, so an unexpected value throws, and the server returns a 500 instead of rejecting the request body. Both decoders now end with the same default case the client template uses:

case discriminatorValue =>
  Left(io.circe.DecodingFailure(s"Unknown discriminator value: $discriminatorValue", cursor.history))

DecodingFailure is fully qualified so the shared import io.circe.{ Decoder, Encoder } stays unchanged for traits without a discriminator.

Tests. I added ScalaHttp4sServerCodegenTest with a spec that has two oneOf unions discriminated on type, one with mapping and one without. The test checks that the keys are "type" in the encoders and decoders, that no HTML-encoded backticks are left, and that both decoders have the default case. It fails on master and passes with this change. I also compiled the server generated from that spec with sbt.

The petstore sample has no discriminator, so ./bin/generate-samples.sh bin/configs/scala-http4s-server.yaml produces no changes.

PR checklist

  • Read the contribution guidelines.
  • Run the following to build the project and update samples:
    ./mvnw clean package || exit
    ./bin/generate-samples.sh ./bin/configs/*.yaml || exit
    ./bin/utils/export_docs_generators.sh || exit
    
    Commit all changed files.
    (Ran the modules/openapi-generator build with its Scala http4s codegen tests and regenerated the scala-http4s-server sample, the only one using this template. No generator options changed, so the generator docs are unaffected.)
  • If your PR is targeting a particular programming language, @mention the technical committee members, so they are more likely to review the pull request.

@clasnake (2017/07), @shijinkui (2018/01), @ramzimaalej (2018/03), @chameleon82 (2020/03), @Bouillie (2020/04) @fish86 (2023/06)


Summary by cubic

Fixes two problems with discriminator codecs in scala-http4s-server/types.mustache: the JSON key now uses the property name instead of the escaped Scala identifier, and unknown discriminator values return a DecodingFailure instead of throwing a MatchError.

  • Encoders and decoders now use propertyBaseName, so reserved words like type are no longer emitted as HTML-escaped backtick identifiers.
  • Both decoders (with and without mapping) now handle unknown discriminator values with a default case returning DecodingFailure.
  • Adds ScalaHttp4sServerCodegenTest with a spec covering discriminated oneOf unions on the reserved word type, with and without mapping.