diff --git a/CHANGELOG.md b/CHANGELOG.md index b6b6cafcc..45418ebef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ ### Changed +- Generating enrichments for generic classes no longer throws the `Slugs should not be generated for field enrichments` error. + ### Remove --- diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt index 1a453b544..745e42b62 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt @@ -11,6 +11,7 @@ import io.bkbn.kompendium.core.util.defaultAuthConfig import io.bkbn.kompendium.core.util.defaultField import io.bkbn.kompendium.core.util.defaultParameter import io.bkbn.kompendium.core.util.doubleConstraints +import io.bkbn.kompendium.core.util.enrichedGenericResponse import io.bkbn.kompendium.core.util.enrichedComplexGenericType import io.bkbn.kompendium.core.util.enrichedNestedCollection import io.bkbn.kompendium.core.util.enrichedSimpleRequest @@ -452,6 +453,9 @@ class KompendiumTest : DescribeSpec({ it("Can enrich a complex generic type") { openApiTestAllSerializers("T0057__enriched_complex_generic_type.json") { enrichedComplexGenericType() } } + it("Can enrich a generic object") { + openApiTestAllSerializers("T0067__enriched_generic_object.json") { enrichedGenericResponse() } + } } describe("Constraints") { it("Can apply constraints to an int field") { diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/util/Enrichment.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/util/Enrichment.kt index 0e8b2451b..546eb506a 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/util/Enrichment.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/util/Enrichment.kt @@ -6,6 +6,7 @@ import io.bkbn.kompendium.core.fixtures.NestedComplexItem import io.bkbn.kompendium.core.fixtures.TestCreatedResponse import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestSimpleRequest +import io.bkbn.kompendium.core.fixtures.GenericObject import io.bkbn.kompendium.core.metadata.GetInfo import io.bkbn.kompendium.core.metadata.PostInfo import io.bkbn.kompendium.core.plugin.NotarizedRoute @@ -135,3 +136,33 @@ fun Routing.enrichedComplexGenericType() { } } } + +fun Routing.enrichedGenericResponse() { + route("/example") { + install(NotarizedRoute()) { + get = GetInfo.builder { + summary(TestModules.defaultPathSummary) + description(TestModules.defaultPathDescription) + response { + responseType( + enrichment = TypeEnrichment("generic") { + GenericObject::data { + description = "A simple description" + typeEnrichment = TypeEnrichment("simple") { + TestSimpleRequest::a { + description = "A simple description" + } + TestSimpleRequest::b { + deprecated = true + } + } + } + } + ) + description("A good response") + responseCode(HttpStatusCode.Created) + } + } + } + } +} diff --git a/core/src/test/resources/T0067__enriched_generic_object.json b/core/src/test/resources/T0067__enriched_generic_object.json new file mode 100644 index 000000000..50abcb5bb --- /dev/null +++ b/core/src/test/resources/T0067__enriched_generic_object.json @@ -0,0 +1,91 @@ +{ + "openapi": "3.1.0", + "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema", + "info": { + "title": "Test API", + "version": "1.33.7", + "description": "An amazing, fully-ish 😉 generated API spec", + "termsOfService": "https://example.com", + "contact": { + "name": "Homer Simpson", + "url": "https://gph.is/1NPUDiM", + "email": "chunkylover53@aol.com" + }, + "license": { + "name": "MIT", + "url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE" + } + }, + "servers": [ + { + "url": "https://myawesomeapi.com", + "description": "Production instance of my API" + }, + { + "url": "https://staging.myawesomeapi.com", + "description": "Where the fun stuff happens" + } + ], + "paths": { + "/example": { + "get": { + "tags": [], + "summary": "Great Summary!", + "description": "testing more", + "parameters": [], + "responses": { + "201": { + "description": "A good response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenericObject-TestSimpleRequest-generic" + } + } + } + } + }, + "deprecated": false + }, + "parameters": [] + } + }, + "webhooks": {}, + "components": { + "schemas": { + "GenericObject-TestSimpleRequest-generic": { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/TestSimpleRequest-simple", + "description": "A simple description" + } + }, + "required": [ + "data" + ] + }, + "TestSimpleRequest-simple": { + "type": "object", + "properties": { + "a": { + "type": "string", + "description": "A simple description" + }, + "b": { + "type": "number", + "format": "int32", + "deprecated": true + } + }, + "required": [ + "a", + "b" + ] + } + }, + "securitySchemes": {} + }, + "security": [], + "tags": [] +} diff --git a/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt b/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt index 00e3c56a8..a84a47ca8 100644 --- a/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt +++ b/core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt @@ -180,6 +180,10 @@ data class SerialNameObject( val camelCaseName: String ) +data class GenericObject( + val data: T +) + enum class Color { RED, GREEN, diff --git a/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/handler/SimpleObjectHandler.kt b/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/handler/SimpleObjectHandler.kt index 386e7c6b1..a28bd20fd 100644 --- a/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/handler/SimpleObjectHandler.kt +++ b/json-schema/src/main/kotlin/io/bkbn/kompendium/json/schema/handler/SimpleObjectHandler.kt @@ -133,8 +133,8 @@ object SimpleObjectHandler { ?: error("This indicates a bug in Kompendium, please open a GitHub issue") return SchemaGenerator.fromTypeToSchema(type, cache, schemaConfigurator, propEnrichment?.typeEnrichment).let { if (it.isOrContainsObjectOrEnumDef()) { - cache[type.getSlug(propEnrichment)] = it - ReferenceDefinition(type.getReferenceSlug(propEnrichment)) + cache[type.getSlug(propEnrichment?.typeEnrichment)] = it + ReferenceDefinition(type.getReferenceSlug(propEnrichment?.typeEnrichment)) } else { it } diff --git a/json-schema/src/test/kotlin/io/bkbn/kompendium/json/schema/SchemaGeneratorTest.kt b/json-schema/src/test/kotlin/io/bkbn/kompendium/json/schema/SchemaGeneratorTest.kt index e45c698d7..9315cb089 100644 --- a/json-schema/src/test/kotlin/io/bkbn/kompendium/json/schema/SchemaGeneratorTest.kt +++ b/json-schema/src/test/kotlin/io/bkbn/kompendium/json/schema/SchemaGeneratorTest.kt @@ -7,11 +7,12 @@ import io.bkbn.kompendium.core.fixtures.ObjectWithEnum import io.bkbn.kompendium.core.fixtures.SerialNameObject import io.bkbn.kompendium.core.fixtures.SimpleEnum import io.bkbn.kompendium.core.fixtures.SlammaJamma -import io.bkbn.kompendium.core.fixtures.TestHelpers.getFileSnapshot import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestSimpleRequest import io.bkbn.kompendium.core.fixtures.TransientObject import io.bkbn.kompendium.core.fixtures.UnbackedObject +import io.bkbn.kompendium.core.fixtures.GenericObject +import io.bkbn.kompendium.core.fixtures.TestHelpers.getFileSnapshot import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.json.schema.definition.JsonSchema import io.kotest.assertions.json.shouldEqualJson @@ -62,6 +63,9 @@ class SchemaGeneratorTest : DescribeSpec({ it("Can generate the schema for object with SerialName annotation") { jsonSchemaTest("T0020__serial_name_object.json") } + it("Can generate the schema for object with generic property") { + jsonSchemaTest>("T0024__generic_object.json") + } } describe("Enums") { it("Can generate the schema for a simple enum") { @@ -135,6 +139,24 @@ class SchemaGeneratorTest : DescribeSpec({ } ) } + it("Can properly assign a reference to a generic object") { + jsonSchemaTest>( + snapshotName = "T0025__enrichment_generic_object.json", + enrichment = TypeEnrichment("generic") { + GenericObject::data { + description = "This is a generic param" + typeEnrichment = TypeEnrichment("simple") { + TestSimpleRequest::a { + description = "This is a simple description" + } + TestSimpleRequest::b { + deprecated = true + } + } + } + } + ) + } } }) { companion object { diff --git a/json-schema/src/test/resources/T0024__generic_object.json b/json-schema/src/test/resources/T0024__generic_object.json new file mode 100644 index 000000000..17f6a2594 --- /dev/null +++ b/json-schema/src/test/resources/T0024__generic_object.json @@ -0,0 +1,11 @@ +{ + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/TestSimpleRequest" + } + }, + "required": [ + "data" + ] +} diff --git a/json-schema/src/test/resources/T0025__enrichment_generic_object.json b/json-schema/src/test/resources/T0025__enrichment_generic_object.json new file mode 100644 index 000000000..ddad55fae --- /dev/null +++ b/json-schema/src/test/resources/T0025__enrichment_generic_object.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "properties": { + "data": { + "description": "This is a generic param", + "$ref": "#/components/schemas/TestSimpleRequest-simple" + } + }, + "required": [ + "data" + ] +}