diff --git a/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/ToKeyedSchemas.scala b/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/ToKeyedSchemas.scala index f809fa188f..1abf0c10af 100644 --- a/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/ToKeyedSchemas.scala +++ b/docs/apispec-docs/src/main/scala/sttp/tapir/docs/apispec/schema/ToKeyedSchemas.scala @@ -1,6 +1,6 @@ package sttp.tapir.docs.apispec.schema -import sttp.tapir.Schema.Title +import sttp.tapir.Schema.{EncodedDiscriminatorValue, Title} import sttp.tapir.{Codec, Schema => TSchema, SchemaType => TSchemaType} private[docs] object ToKeyedSchemas { @@ -53,6 +53,8 @@ private[docs] object ToKeyedSchemas { if (s1.deprecated != s2.deprecated) result = result.deprecated(false) if (s1.attributes.get(Title.Attribute) != s2.attributes.get(Title.Attribute)) result = result.copy(attributes = result.attributes.remove(Title.Attribute)) + if (s1.attributes.get(EncodedDiscriminatorValue.Attribute) != s2.attributes.get(EncodedDiscriminatorValue.Attribute)) + result = result.copy(attributes = result.attributes.remove(EncodedDiscriminatorValue.Attribute)) result } } diff --git a/docs/openapi-docs/src/test/resources/coproduct/expected_coproduct_discriminator_enum.yml b/docs/openapi-docs/src/test/resources/coproduct/expected_coproduct_discriminator_enum.yml new file mode 100644 index 0000000000..e02a9d29b8 --- /dev/null +++ b/docs/openapi-docs/src/test/resources/coproduct/expected_coproduct_discriminator_enum.yml @@ -0,0 +1,63 @@ +openapi: 3.1.0 +info: + title: title + version: '1.0' +paths: + /figure: + post: + operationId: postFigure + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + '200': + description: '' + '400': + description: 'Invalid value for: body' + content: + text/plain: + schema: + type: string +components: + schemas: + Cat: + title: Cat + type: object + required: + - name + - petType + properties: + name: + type: string + petType: + $ref: '#/components/schemas/PetType' + Dog: + title: Dog + type: object + required: + - breed + - petType + properties: + breed: + type: string + petType: + $ref: '#/components/schemas/PetType' + Pet: + title: Pet + oneOf: + - $ref: '#/components/schemas/Cat' + - $ref: '#/components/schemas/Dog' + discriminator: + propertyName: petType + mapping: + Canine: '#/components/schemas/Dog' + Feline: '#/components/schemas/Cat' + PetType: + title: PetType + type: string + enum: + - Canine + - Feline \ No newline at end of file diff --git a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlCoproductTest.scala b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlCoproductTest.scala index f3e9fe0dc1..91edff774d 100644 --- a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlCoproductTest.scala +++ b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/VerifyYamlCoproductTest.scala @@ -167,4 +167,16 @@ class VerifyYamlCoproductTest extends AnyFunSuite with Matchers { noIndentation(actualYaml) shouldBe expectedYaml } + + test("coproduct using an enum discriminator, added using `.addDiscriminatorField`") { + val petEndpoint = endpoint.post + .in("figure") + .in(jsonBody[Pet]) + + val expectedYaml = load("coproduct/expected_coproduct_discriminator_enum.yml") + + val actualYaml = OpenAPIDocsInterpreter().toOpenAPI(List(petEndpoint), "title", "1.0").toYaml + + noIndentation(actualYaml) shouldBe expectedYaml + } } diff --git a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/dtos/VerifyYamlCoproductTestData.scala b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/dtos/VerifyYamlCoproductTestData.scala index c270d507e5..e1c59181d4 100644 --- a/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/dtos/VerifyYamlCoproductTestData.scala +++ b/docs/openapi-docs/src/test/scalajvm/sttp/tapir/docs/openapi/dtos/VerifyYamlCoproductTestData.scala @@ -2,6 +2,10 @@ package sttp.tapir.docs.openapi.dtos import sttp.tapir.tests.data.Entity import sttp.tapir.{Schema, Validator} +import sttp.tapir.SchemaType.SRef +import sttp.tapir.Schema.SName +import sttp.tapir.SchemaType +import sttp.tapir.FieldName // TODO: move back to VerifyYamlTest companion after https://github.com/lampepfl/dotty/issues/12849 is fixed object VerifyYamlCoproductTestData { @@ -24,4 +28,30 @@ object VerifyYamlCoproductTestData { } case class Square(color: Color.Value, shapeType: String = "square") extends Shape + + sealed trait PetType + object PetType { + case object Canine extends PetType + case object Feline extends PetType + implicit val schema: Schema[PetType] = Schema.derivedEnumeration[PetType].defaultStringBased + } + + sealed trait Pet + object Pet { + implicit val schema: Schema[Pet] = { + val derived = Schema.derived[Pet] + val mapping = Map( + PetType.Canine.toString -> SRef(SName("sttp.tapir.docs.openapi.dtos.VerifyYamlCoproductTestData.Dog")), + PetType.Feline.toString -> SRef(SName("sttp.tapir.docs.openapi.dtos.VerifyYamlCoproductTestData.Cat")) + ) + + derived.schemaType match { + case s: SchemaType.SCoproduct[Pet] => + derived.copy(schemaType = s.addDiscriminatorField(FieldName("petType"), PetType.schema, mapping)) + case _ => derived + } + } + } + final case class Dog(breed: String) extends Pet + final case class Cat(name: String) extends Pet }