diff --git a/zio-http/src/main/scala/zio/http/endpoint/openapi/JsonSchema.scala b/zio-http/src/main/scala/zio/http/endpoint/openapi/JsonSchema.scala index e2128f9fe9..5292fff449 100644 --- a/zio-http/src/main/scala/zio/http/endpoint/openapi/JsonSchema.scala +++ b/zio-http/src/main/scala/zio/http/endpoint/openapi/JsonSchema.scala @@ -349,12 +349,11 @@ object JsonSchema { val children = record.fields .filterNot(_.annotations.exists(_.isInstanceOf[transientField])) .flatMap { field => - val key = nominal(field.schema, refType).orElse(nominal(field.schema, SchemaStyle.Compact)) val nested = fromZSchemaMulti( field.schema, refType, ) - key.map(k => nested.children + (k -> nested.root)).getOrElse(nested.children) + nested.rootRef.map(k => nested.children + (k -> nested.root)).getOrElse(nested.children) } .toMap JsonSchemas(fromZSchema(record, SchemaStyle.Inline), ref, children) @@ -496,7 +495,7 @@ object JsonSchema { ) .addAll(nonTransientFields.map { field => field.name -> - fromZSchema(field.schema, refType) + fromZSchema(field.schema, SchemaStyle.Compact) .deprecated(deprecated(field.schema)) .description(fieldDoc(field)) .default(fieldDefault(field)) diff --git a/zio-http/src/test/scala/zio/http/endpoint/openapi/OpenAPIGenSpec.scala b/zio-http/src/test/scala/zio/http/endpoint/openapi/OpenAPIGenSpec.scala index 9cac9342ec..0695de4e62 100644 --- a/zio-http/src/test/scala/zio/http/endpoint/openapi/OpenAPIGenSpec.scala +++ b/zio-http/src/test/scala/zio/http/endpoint/openapi/OpenAPIGenSpec.scala @@ -47,6 +47,10 @@ object OpenAPIGenSpec extends ZIOSpecDefault { implicit val withOptionalFieldSchema: Schema[WithOptionalField] = DeriveSchema.gen[WithOptionalField] + final case class NestedProduct(imageMetadata: ImageMetadata, withOptionalField: WithOptionalField) + implicit val nestedProductSchema: Schema[NestedProduct] = + DeriveSchema.gen[NestedProduct] + sealed trait SimpleEnum object SimpleEnum { implicit val schema: Schema[SimpleEnum] = DeriveSchema.gen[SimpleEnum] @@ -1631,31 +1635,35 @@ object OpenAPIGenSpec extends ZIOSpecDefault { | }, | "components" : { | "schemas" : { + | "ImageMetadata" : + | { + | "type" : + | "object", + | "properties" : { + | "name" : { + | "type" : + | "string" + | }, + | "size" : { + | "type" : + | "integer", + | "format" : "int32" + | } + | }, + | "additionalProperties" : + | true, + | "required" : [ + | "name", + | "size" + | ] + | }, | "WithComplexDefaultValue" : | { | "type" : | "object", | "properties" : { | "data" : { - | "type" : - | "object", - | "properties" : { - | "name" : { - | "type" : - | "string" - | }, - | "size" : { - | "type" : - | "integer", - | "format" : "int32" - | } - | }, - | "additionalProperties" : - | true, - | "required" : [ - | "name", - | "size" - | ], + | "$ref" : "#/components/schemas/ImageMetadata", | "description" : "If not set, this field defaults to the value of the default annotation.", | "default" : { | "name" : "default", @@ -1728,6 +1736,105 @@ object OpenAPIGenSpec extends ZIOSpecDefault { |}""".stripMargin assertTrue(json == toJsonAst(expected)) }, + test("nested product") { + val endpoint = Endpoint(GET / "static").in[NestedProduct] + val generated = OpenAPIGen.fromEndpoints("Simple Endpoint", "1.0", endpoint) + println(generated.toJsonPretty) + val json = toJsonAst(generated) + val expected = """{ + | "openapi" : "3.1.0", + | "info" : { + | "title" : "Simple Endpoint", + | "version" : "1.0" + | }, + | "paths" : { + | "/static" : { + | "get" : { + | "requestBody" : + | { + | "content" : { + | "application/json" : { + | "schema" : + | { + | "$ref" : "#/components/schemas/NestedProduct" + | } + | } + | }, + | "required" : true + | }, + | "deprecated" : false + | } + | } + | }, + | "components" : { + | "schemas" : { + | "ImageMetadata" : + | { + | "type" : + | "object", + | "properties" : { + | "name" : { + | "type" : + | "string" + | }, + | "size" : { + | "type" : + | "integer", + | "format" : "int32" + | } + | }, + | "additionalProperties" : + | true, + | "required" : [ + | "name", + | "size" + | ] + | }, + | "WithOptionalField" : + | { + | "type" : + | "object", + | "properties" : { + | "name" : { + | "type" : + | "string" + | }, + | "age" : { + | "type" : + | "integer", + | "format" : "int32" + | } + | }, + | "additionalProperties" : + | true, + | "required" : [ + | "name" + | ] + | }, + | "NestedProduct" : + | { + | "type" : + | "object", + | "properties" : { + | "imageMetadata" : { + | "$ref" : "#/components/schemas/ImageMetadata" + | }, + | "withOptionalField" : { + | "$ref" : "#/components/schemas/WithOptionalField" + | } + | }, + | "additionalProperties" : + | true, + | "required" : [ + | "imageMetadata", + | "withOptionalField" + | ] + | } + | } + | } + |}""".stripMargin + assertTrue(json == toJsonAst(expected)) + }, test("enum") { val endpoint = Endpoint(GET / "static").in[SimpleEnum] val generated = OpenAPIGen.fromEndpoints("Simple Endpoint", "1.0", endpoint) @@ -2091,6 +2198,7 @@ object OpenAPIGenSpec extends ZIOSpecDefault { test("sealed trait with nested sealed trait") { val endpoint = Endpoint(GET / "static").in[SimpleNestedSealedTrait] val generated = OpenAPIGen.fromEndpoints("Simple Endpoint", "1.0", endpoint) + println(generated.toJsonPretty) val json = toJsonAst(generated) val expectedJson = """{ @@ -2120,6 +2228,20 @@ object OpenAPIGenSpec extends ZIOSpecDefault { | }, | "components" : { | "schemas" : { + | "SealedTraitNoDiscriminator" : + | { + | "oneOf" : [ + | { + | "$ref" : "#/components/schemas/One" + | }, + | { + | "$ref" : "#/components/schemas/Two" + | }, + | { + | "$ref" : "#/components/schemas/Three" + | } + | ] + | }, | "NestedOne" : | { | "type" : @@ -2150,17 +2272,7 @@ object OpenAPIGenSpec extends ZIOSpecDefault { | "object", | "properties" : { | "name" : { - | "oneOf" : [ - | { - | "$ref" : "#/components/schemas/One" - | }, - | { - | "$ref" : "#/components/schemas/Two" - | }, - | { - | "$ref" : "#/components/schemas/Three" - | } - | ] + | "$ref" : "#/components/schemas/SealedTraitNoDiscriminator" | } | }, | "additionalProperties" :