From d54b8a730fa204aae5468160c175006df11fc594 Mon Sep 17 00:00:00 2001 From: Ryan Brink <5607577+unredundant@users.noreply.github.com> Date: Fri, 4 Feb 2022 12:34:21 -0500 Subject: [PATCH] fix: support recursive types (#174) --- CHANGELOG.md | 4 + gradle.properties | 2 +- .../bkbn/kompendium/annotations/Referenced.kt | 11 ++ .../notarized_basic_authenticated_get.json | 1 + .../notarized_jwt_authenticated_get.json | 1 + .../resources/notarized_oauth_all_flows.json | 1 + .../kompendium/core/KompendiumPreFlight.kt | 38 ++++++ .../kotlin/io/bkbn/kompendium/core/Kontent.kt | 9 ++ .../io/bkbn/kompendium/core/util/Helpers.kt | 4 +- .../io/bkbn/kompendium/core/KompendiumTest.kt | 4 + .../bkbn/kompendium/core/util/TestModules.kt | 10 ++ .../src/test/resources/complex_type.json | 1 + .../resources/crazy_polymorphic_example.json | 1 + .../src/test/resources/default_field.json | 1 + .../src/test/resources/default_param.json | 1 + .../test/resources/example_parameters.json | 1 + .../test/resources/example_req_and_resp.json | 1 + .../src/test/resources/exclusive_min_max.json | 1 + .../src/test/resources/field_override.json | 1 + .../test/resources/formatted_param_type.json | 1 + .../src/test/resources/free_form_object.json | 1 + .../src/test/resources/generic_exception.json | 1 + .../src/test/resources/generic_response.json | 1 + .../src/test/resources/min_max_array.json | 1 + .../test/resources/min_max_double_field.json | 1 + .../src/test/resources/min_max_free_form.json | 1 + .../src/test/resources/min_max_int_field.json | 1 + .../src/test/resources/min_max_string.json | 1 + .../test/resources/multiple_of_double.json | 1 + .../src/test/resources/multiple_of_int.json | 1 + .../src/test/resources/nested_under_root.json | 1 + .../test/resources/non_required_params.json | 1 + .../src/test/resources/notarized_delete.json | 1 + .../src/test/resources/notarized_get.json | 1 + ...notarized_get_with_exception_response.json | 1 + ...get_with_multiple_exception_responses.json | 1 + .../notarized_get_with_operation_id.json | 1 + .../src/test/resources/notarized_head.json | 1 + .../src/test/resources/notarized_options.json | 1 + .../src/test/resources/notarized_patch.json | 1 + .../src/test/resources/notarized_post.json | 1 + .../test/resources/notarized_primitives.json | 1 + .../src/test/resources/notarized_put.json | 1 + .../src/test/resources/nullable_field.json | 1 + .../resources/override_parameter_name.json | 1 + .../src/test/resources/path_parser.json | 1 + .../polymorphic_error_status_codes.json | 1 + .../resources/polymorphic_list_response.json | 1 + .../resources/polymorphic_map_response.json | 1 + .../test/resources/polymorphic_response.json | 1 + .../polymorphic_response_with_generics.json | 1 + .../query_with_default_parameter.json | 1 + .../src/test/resources/regex_string.json | 1 + .../src/test/resources/required_param.json | 1 + .../src/test/resources/response_list.json | 1 + .../src/test/resources/root_route.json | 1 + .../resources/sealed_interface_response.json | 80 ++++++++++++ .../src/test/resources/simple_recursive.json | 123 ++++++++++++++++++ .../src/test/resources/trailing_slash.json | 1 + .../src/test/resources/undeclared_field.json | 1 + .../src/test/resources/unique_array.json | 1 + .../kompendium/core/fixtures/TestModels.kt | 20 ++- .../core/fixtures/TestResponseInfo.kt | 10 +- .../notarized_delete_nested_location.json | 1 + .../notarized_delete_simple_location.json | 1 + .../notarized_get_nested_location.json | 1 + .../notarized_get_simple_location.json | 1 + .../notarized_post_nested_location.json | 1 + .../notarized_post_simple_location.json | 1 + .../notarized_put_nested_location.json | 1 + .../notarized_put_simple_location.json | 1 + .../kompendium/oas/component/Components.kt | 2 + .../kompendium/oas/schema/ComponentSchema.kt | 4 + .../kompendium/oas/schema/FreeFormSchema.kt | 5 +- .../kompendium/oas/schema/ReferencedSchema.kt | 11 ++ .../KompendiumSerializersModule.kt | 2 + .../playground/RecursionPlayground.kt | 97 ++++++++++++++ 77 files changed, 487 insertions(+), 8 deletions(-) create mode 100644 kompendium-annotations/src/main/kotlin/io/bkbn/kompendium/annotations/Referenced.kt create mode 100644 kompendium-core/src/test/resources/simple_recursive.json create mode 100644 kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ReferencedSchema.kt create mode 100644 kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/RecursionPlayground.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 62e032392..03991fa15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ ## Released +## [2.0.2] - February 4th, 2022 +### Added +- `@Referenced` annotation enabling support for recursive models + ## [2.0.1] - January 23rd, 2022 ### Change diff --git a/gradle.properties b/gradle.properties index c3e949933..209a49e13 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Kompendium -project.version=2.0.1 +project.version=2.0.2 # Kotlin kotlin.code.style=official # Gradle diff --git a/kompendium-annotations/src/main/kotlin/io/bkbn/kompendium/annotations/Referenced.kt b/kompendium-annotations/src/main/kotlin/io/bkbn/kompendium/annotations/Referenced.kt new file mode 100644 index 000000000..60853a46e --- /dev/null +++ b/kompendium-annotations/src/main/kotlin/io/bkbn/kompendium/annotations/Referenced.kt @@ -0,0 +1,11 @@ +package io.bkbn.kompendium.annotations + +/** + * This instructs Kompendium to store the class as a referenced component. + * This is mandatory for any data models that have recursive children. + * If you do not annotate a recursive class with [Referenced], you will + * get a stack overflow error when you try to launch your API + */ +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class Referenced diff --git a/kompendium-auth/src/test/resources/notarized_basic_authenticated_get.json b/kompendium-auth/src/test/resources/notarized_basic_authenticated_get.json index 3695f4139..e098961c5 100644 --- a/kompendium-auth/src/test/resources/notarized_basic_authenticated_get.json +++ b/kompendium-auth/src/test/resources/notarized_basic_authenticated_get.json @@ -82,6 +82,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": { "basic": { "type": "http", diff --git a/kompendium-auth/src/test/resources/notarized_jwt_authenticated_get.json b/kompendium-auth/src/test/resources/notarized_jwt_authenticated_get.json index b6c476623..661bf8057 100644 --- a/kompendium-auth/src/test/resources/notarized_jwt_authenticated_get.json +++ b/kompendium-auth/src/test/resources/notarized_jwt_authenticated_get.json @@ -82,6 +82,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": { "jwt": { "bearerFormat": "JWT", diff --git a/kompendium-auth/src/test/resources/notarized_oauth_all_flows.json b/kompendium-auth/src/test/resources/notarized_oauth_all_flows.json index a530afb97..ed2b82bd1 100644 --- a/kompendium-auth/src/test/resources/notarized_oauth_all_flows.json +++ b/kompendium-auth/src/test/resources/notarized_oauth_all_flows.json @@ -82,6 +82,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": { "oauth": { "flows": { diff --git a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/KompendiumPreFlight.kt b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/KompendiumPreFlight.kt index 5c20aa6e4..ee094e201 100644 --- a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/KompendiumPreFlight.kt +++ b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/KompendiumPreFlight.kt @@ -1,5 +1,16 @@ package io.bkbn.kompendium.core +import io.bkbn.kompendium.core.util.Helpers.COMPONENT_SLUG +import io.bkbn.kompendium.oas.schema.AnyOfSchema +import io.bkbn.kompendium.oas.schema.ArraySchema +import io.bkbn.kompendium.oas.schema.ComponentSchema +import io.bkbn.kompendium.oas.schema.DictionarySchema +import io.bkbn.kompendium.oas.schema.EnumSchema +import io.bkbn.kompendium.oas.schema.FormattedSchema +import io.bkbn.kompendium.oas.schema.FreeFormSchema +import io.bkbn.kompendium.oas.schema.ObjectSchema +import io.bkbn.kompendium.oas.schema.ReferencedSchema +import io.bkbn.kompendium.oas.schema.SimpleSchema import io.ktor.application.feature import io.ktor.routing.Route import io.ktor.routing.application @@ -35,5 +46,32 @@ object KompendiumPreFlight { feature.config.cache = Kontent.generateKontent(requestType, feature.config.cache) feature.config.cache = Kontent.generateKontent(responseType, feature.config.cache) feature.config.cache = Kontent.generateKontent(paramType, feature.config.cache) + feature.updateReferences() + } + + private fun Kompendium.updateReferences() { + val references = config.cache.values + .asSequence() + .map { flattenSchema(it) } + .flatten() + .filterIsInstance() + .map { it.`$ref` } + .map { it.replace(COMPONENT_SLUG.plus("/"), "") } + .toList() + references.forEach { ref -> + config.spec.components.schemas[ref] = config.cache[ref] ?: error("$ref does not exist in cache 😱") + } + } + + private fun flattenSchema(schema: ComponentSchema): List = when (schema) { + is AnyOfSchema -> schema.anyOf.map { flattenSchema(it) }.flatten() + is ReferencedSchema -> listOf(schema) + is ArraySchema -> flattenSchema(schema.items) + is DictionarySchema -> flattenSchema(schema.additionalProperties) + is EnumSchema -> listOf(schema) + is FormattedSchema -> listOf(schema) + is FreeFormSchema -> listOf(schema) + is ObjectSchema -> schema.properties.values.map { flattenSchema(it) }.flatten() + is SimpleSchema -> listOf(schema) } } diff --git a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kontent.kt b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kontent.kt index 9cead6e80..b1289f08d 100644 --- a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kontent.kt +++ b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kontent.kt @@ -2,6 +2,7 @@ package io.bkbn.kompendium.core import io.bkbn.kompendium.annotations.Field import io.bkbn.kompendium.annotations.FreeFormObject +import io.bkbn.kompendium.annotations.Referenced import io.bkbn.kompendium.annotations.UndeclaredField import io.bkbn.kompendium.annotations.constraint.Format import io.bkbn.kompendium.annotations.constraint.MaxItems @@ -18,6 +19,7 @@ import io.bkbn.kompendium.annotations.constraint.UniqueItems import io.bkbn.kompendium.core.metadata.SchemaMap import io.bkbn.kompendium.core.metadata.TypeMap import io.bkbn.kompendium.core.util.Helpers.genericNameAdapter +import io.bkbn.kompendium.core.util.Helpers.getReferenceSlug import io.bkbn.kompendium.core.util.Helpers.getSimpleSlug import io.bkbn.kompendium.core.util.Helpers.logged import io.bkbn.kompendium.core.util.Helpers.toNumber @@ -29,6 +31,7 @@ import io.bkbn.kompendium.oas.schema.EnumSchema import io.bkbn.kompendium.oas.schema.FormattedSchema import io.bkbn.kompendium.oas.schema.FreeFormSchema import io.bkbn.kompendium.oas.schema.ObjectSchema +import io.bkbn.kompendium.oas.schema.ReferencedSchema import io.bkbn.kompendium.oas.schema.SimpleSchema import kotlin.reflect.KClass import kotlin.reflect.KClassifier @@ -36,6 +39,7 @@ import kotlin.reflect.KProperty1 import kotlin.reflect.KType import kotlin.reflect.full.createType import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.hasAnnotation import kotlin.reflect.full.isSubclassOf import kotlin.reflect.full.memberProperties import kotlin.reflect.full.primaryConstructor @@ -144,6 +148,10 @@ object Kontent { false -> { logger.debug("$slug was not found in cache, generating now") var newCache = cache + // If referenced, add tie from simple slug to schema slug + if (clazz.hasAnnotation()) { + newCache = newCache.plus(type.getSimpleSlug() to ReferencedSchema(type.getReferenceSlug())) + } // Grabs any type parameters mapped to the corresponding type argument(s) val typeMap: TypeMap = clazz.typeParameters.zip(type.arguments).toMap() // associates each member with a Pair of prop name to property schema @@ -274,6 +282,7 @@ object Kontent { is FreeFormSchema -> this // todo anything here? is ObjectSchema -> scanForConstraints(clazz, prop) is SimpleSchema -> scanForConstraints(prop) + is ReferencedSchema -> this // todo anything here? } private fun ArraySchema.scanForConstraints(prop: KProperty1<*, *>): ArraySchema { diff --git a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt index 9628ee4c1..326aeffdf 100644 --- a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt +++ b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt @@ -1,19 +1,19 @@ package io.bkbn.kompendium.core.util -import java.lang.reflect.ParameterizedType import kotlin.reflect.KClass import kotlin.reflect.KProperty import kotlin.reflect.KType import kotlin.reflect.full.createType import kotlin.reflect.jvm.javaField import org.slf4j.LoggerFactory +import java.lang.reflect.ParameterizedType import java.util.Locale object Helpers { private val logger = LoggerFactory.getLogger(javaClass) - private const val COMPONENT_SLUG = "#/components/schemas" + const val COMPONENT_SLUG = "#/components/schemas" val UNIT_TYPE by lazy { Unit::class.createType() } diff --git a/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt b/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt index d3efd9b13..0e5c42bdc 100644 --- a/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt +++ b/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt @@ -46,6 +46,7 @@ import io.bkbn.kompendium.core.util.requiredParameter import io.bkbn.kompendium.core.util.returnsList import io.bkbn.kompendium.core.util.rootModule import io.bkbn.kompendium.core.util.simpleGenericResponse +import io.bkbn.kompendium.core.util.simpleRecursive import io.bkbn.kompendium.core.util.trailingSlash import io.bkbn.kompendium.core.util.undeclaredType import io.bkbn.kompendium.core.util.uniqueArray @@ -213,6 +214,9 @@ class KompendiumTest : DescribeSpec({ it("Can override field values via annotation") { openApiTest("field_override.json") { overrideFieldInfo() } } + it("Can serialize a recursive type using references") { + openApiTest("simple_recursive.json") { simpleRecursive() } + } } describe("Constraints") { it("Can set a minimum and maximum integer value") { diff --git a/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt b/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt index c6ecbd9ae..6c13d8f02 100644 --- a/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt +++ b/kompendium-core/src/test/kotlin/io/bkbn/kompendium/core/util/TestModules.kt @@ -405,6 +405,16 @@ fun Application.overrideFieldInfo() { } } +fun Application.simpleRecursive() { + routing { + route("/test/simple_recursive") { + notarizedGet(TestResponseInfo.simpleRecursive) { + call.respond(HttpStatusCode.OK) + } + } + } +} + fun Application.constrainedIntInfo() { routing { route("/test/constrained_int") { diff --git a/kompendium-core/src/test/resources/complex_type.json b/kompendium-core/src/test/resources/complex_type.json index 4b4c5f813..9aa3f0dc8 100644 --- a/kompendium-core/src/test/resources/complex_type.json +++ b/kompendium-core/src/test/resources/complex_type.json @@ -119,6 +119,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/crazy_polymorphic_example.json b/kompendium-core/src/test/resources/crazy_polymorphic_example.json index d80f6640b..bd1041171 100644 --- a/kompendium-core/src/test/resources/crazy_polymorphic_example.json +++ b/kompendium-core/src/test/resources/crazy_polymorphic_example.json @@ -196,6 +196,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/default_field.json b/kompendium-core/src/test/resources/default_field.json index f31bcb362..07479ddb1 100644 --- a/kompendium-core/src/test/resources/default_field.json +++ b/kompendium-core/src/test/resources/default_field.json @@ -80,6 +80,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/default_param.json b/kompendium-core/src/test/resources/default_param.json index 05934e56b..63fda08b8 100644 --- a/kompendium-core/src/test/resources/default_param.json +++ b/kompendium-core/src/test/resources/default_param.json @@ -68,6 +68,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/example_parameters.json b/kompendium-core/src/test/resources/example_parameters.json index 6d9508c26..f1720753d 100644 --- a/kompendium-core/src/test/resources/example_parameters.json +++ b/kompendium-core/src/test/resources/example_parameters.json @@ -90,6 +90,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/example_req_and_resp.json b/kompendium-core/src/test/resources/example_req_and_resp.json index 9a20d0a53..ec643b959 100644 --- a/kompendium-core/src/test/resources/example_req_and_resp.json +++ b/kompendium-core/src/test/resources/example_req_and_resp.json @@ -126,6 +126,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/exclusive_min_max.json b/kompendium-core/src/test/resources/exclusive_min_max.json index 898f2449b..3bc913330 100644 --- a/kompendium-core/src/test/resources/exclusive_min_max.json +++ b/kompendium-core/src/test/resources/exclusive_min_max.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/field_override.json b/kompendium-core/src/test/resources/field_override.json index a69f50efa..263ef3282 100644 --- a/kompendium-core/src/test/resources/field_override.json +++ b/kompendium-core/src/test/resources/field_override.json @@ -58,6 +58,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/formatted_param_type.json b/kompendium-core/src/test/resources/formatted_param_type.json index 076280f34..8f8c4e292 100644 --- a/kompendium-core/src/test/resources/formatted_param_type.json +++ b/kompendium-core/src/test/resources/formatted_param_type.json @@ -68,6 +68,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/free_form_object.json b/kompendium-core/src/test/resources/free_form_object.json index 87aa0e387..5330de253 100644 --- a/kompendium-core/src/test/resources/free_form_object.json +++ b/kompendium-core/src/test/resources/free_form_object.json @@ -58,6 +58,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/generic_exception.json b/kompendium-core/src/test/resources/generic_exception.json index a98f3900c..f0ee642c1 100644 --- a/kompendium-core/src/test/resources/generic_exception.json +++ b/kompendium-core/src/test/resources/generic_exception.json @@ -114,6 +114,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/generic_response.json b/kompendium-core/src/test/resources/generic_response.json index a4755e772..c68948d55 100644 --- a/kompendium-core/src/test/resources/generic_response.json +++ b/kompendium-core/src/test/resources/generic_response.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/min_max_array.json b/kompendium-core/src/test/resources/min_max_array.json index 11dd22b6f..3b6bfb307 100644 --- a/kompendium-core/src/test/resources/min_max_array.json +++ b/kompendium-core/src/test/resources/min_max_array.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/min_max_double_field.json b/kompendium-core/src/test/resources/min_max_double_field.json index 746392257..06db3702d 100644 --- a/kompendium-core/src/test/resources/min_max_double_field.json +++ b/kompendium-core/src/test/resources/min_max_double_field.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/min_max_free_form.json b/kompendium-core/src/test/resources/min_max_free_form.json index 9a1b07406..1353df134 100644 --- a/kompendium-core/src/test/resources/min_max_free_form.json +++ b/kompendium-core/src/test/resources/min_max_free_form.json @@ -60,6 +60,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/min_max_int_field.json b/kompendium-core/src/test/resources/min_max_int_field.json index 37b1afcae..59bf2d7f0 100644 --- a/kompendium-core/src/test/resources/min_max_int_field.json +++ b/kompendium-core/src/test/resources/min_max_int_field.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/min_max_string.json b/kompendium-core/src/test/resources/min_max_string.json index 482dcbbfa..9a88a35b4 100644 --- a/kompendium-core/src/test/resources/min_max_string.json +++ b/kompendium-core/src/test/resources/min_max_string.json @@ -59,6 +59,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/multiple_of_double.json b/kompendium-core/src/test/resources/multiple_of_double.json index 22b293a23..e23ca0ed0 100644 --- a/kompendium-core/src/test/resources/multiple_of_double.json +++ b/kompendium-core/src/test/resources/multiple_of_double.json @@ -59,6 +59,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/multiple_of_int.json b/kompendium-core/src/test/resources/multiple_of_int.json index a1350fc21..70eaa522a 100644 --- a/kompendium-core/src/test/resources/multiple_of_int.json +++ b/kompendium-core/src/test/resources/multiple_of_int.json @@ -59,6 +59,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/nested_under_root.json b/kompendium-core/src/test/resources/nested_under_root.json index c3d4d1b45..947a6e684 100644 --- a/kompendium-core/src/test/resources/nested_under_root.json +++ b/kompendium-core/src/test/resources/nested_under_root.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/non_required_params.json b/kompendium-core/src/test/resources/non_required_params.json index 88586e6d8..0fd6cdadb 100644 --- a/kompendium-core/src/test/resources/non_required_params.json +++ b/kompendium-core/src/test/resources/non_required_params.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_delete.json b/kompendium-core/src/test/resources/notarized_delete.json index db1a8ce35..7cdfe569f 100644 --- a/kompendium-core/src/test/resources/notarized_delete.json +++ b/kompendium-core/src/test/resources/notarized_delete.json @@ -56,6 +56,7 @@ } }, "components" : { + "schemas": {}, "securitySchemes" : { } }, "security" : [ ], diff --git a/kompendium-core/src/test/resources/notarized_get.json b/kompendium-core/src/test/resources/notarized_get.json index 32f18d138..be4848ab2 100644 --- a/kompendium-core/src/test/resources/notarized_get.json +++ b/kompendium-core/src/test/resources/notarized_get.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_get_with_exception_response.json b/kompendium-core/src/test/resources/notarized_get_with_exception_response.json index 78c597928..2a53e7ad2 100644 --- a/kompendium-core/src/test/resources/notarized_get_with_exception_response.json +++ b/kompendium-core/src/test/resources/notarized_get_with_exception_response.json @@ -95,6 +95,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_get_with_multiple_exception_responses.json b/kompendium-core/src/test/resources/notarized_get_with_multiple_exception_responses.json index a603b8815..0cf741368 100644 --- a/kompendium-core/src/test/resources/notarized_get_with_multiple_exception_responses.json +++ b/kompendium-core/src/test/resources/notarized_get_with_multiple_exception_responses.json @@ -113,6 +113,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_get_with_operation_id.json b/kompendium-core/src/test/resources/notarized_get_with_operation_id.json index c3880a913..49a29eaf3 100644 --- a/kompendium-core/src/test/resources/notarized_get_with_operation_id.json +++ b/kompendium-core/src/test/resources/notarized_get_with_operation_id.json @@ -78,6 +78,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_head.json b/kompendium-core/src/test/resources/notarized_head.json index 0090603eb..eeb33cb97 100644 --- a/kompendium-core/src/test/resources/notarized_head.json +++ b/kompendium-core/src/test/resources/notarized_head.json @@ -42,6 +42,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_options.json b/kompendium-core/src/test/resources/notarized_options.json index 76c220088..fbbcc34d9 100644 --- a/kompendium-core/src/test/resources/notarized_options.json +++ b/kompendium-core/src/test/resources/notarized_options.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_patch.json b/kompendium-core/src/test/resources/notarized_patch.json index 79f7bbfad..04d8b61c2 100644 --- a/kompendium-core/src/test/resources/notarized_patch.json +++ b/kompendium-core/src/test/resources/notarized_patch.json @@ -57,6 +57,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_post.json b/kompendium-core/src/test/resources/notarized_post.json index b5f1055a7..62081c701 100644 --- a/kompendium-core/src/test/resources/notarized_post.json +++ b/kompendium-core/src/test/resources/notarized_post.json @@ -122,6 +122,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_primitives.json b/kompendium-core/src/test/resources/notarized_primitives.json index a237b2488..1a4c68dd1 100644 --- a/kompendium-core/src/test/resources/notarized_primitives.json +++ b/kompendium-core/src/test/resources/notarized_primitives.json @@ -61,6 +61,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/notarized_put.json b/kompendium-core/src/test/resources/notarized_put.json index 55e0b4766..b4590ae8c 100644 --- a/kompendium-core/src/test/resources/notarized_put.json +++ b/kompendium-core/src/test/resources/notarized_put.json @@ -122,6 +122,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/nullable_field.json b/kompendium-core/src/test/resources/nullable_field.json index 4874dd182..ae05c8e69 100644 --- a/kompendium-core/src/test/resources/nullable_field.json +++ b/kompendium-core/src/test/resources/nullable_field.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/override_parameter_name.json b/kompendium-core/src/test/resources/override_parameter_name.json index ed8fe5413..5451afebb 100644 --- a/kompendium-core/src/test/resources/override_parameter_name.json +++ b/kompendium-core/src/test/resources/override_parameter_name.json @@ -67,6 +67,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/path_parser.json b/kompendium-core/src/test/resources/path_parser.json index 7d1a3fabf..504a5c6d5 100644 --- a/kompendium-core/src/test/resources/path_parser.json +++ b/kompendium-core/src/test/resources/path_parser.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/polymorphic_error_status_codes.json b/kompendium-core/src/test/resources/polymorphic_error_status_codes.json index 76f5b0241..cc97fa4a0 100644 --- a/kompendium-core/src/test/resources/polymorphic_error_status_codes.json +++ b/kompendium-core/src/test/resources/polymorphic_error_status_codes.json @@ -115,6 +115,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/polymorphic_list_response.json b/kompendium-core/src/test/resources/polymorphic_list_response.json index 63764f249..6d0e8dd69 100644 --- a/kompendium-core/src/test/resources/polymorphic_list_response.json +++ b/kompendium-core/src/test/resources/polymorphic_list_response.json @@ -80,6 +80,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/polymorphic_map_response.json b/kompendium-core/src/test/resources/polymorphic_map_response.json index cb0e80c35..d72cc8558 100644 --- a/kompendium-core/src/test/resources/polymorphic_map_response.json +++ b/kompendium-core/src/test/resources/polymorphic_map_response.json @@ -80,6 +80,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/polymorphic_response.json b/kompendium-core/src/test/resources/polymorphic_response.json index a5c9cb0a6..420c3d65a 100644 --- a/kompendium-core/src/test/resources/polymorphic_response.json +++ b/kompendium-core/src/test/resources/polymorphic_response.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/polymorphic_response_with_generics.json b/kompendium-core/src/test/resources/polymorphic_response_with_generics.json index 7b7302e4e..d30af8d76 100644 --- a/kompendium-core/src/test/resources/polymorphic_response_with_generics.json +++ b/kompendium-core/src/test/resources/polymorphic_response_with_generics.json @@ -92,6 +92,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/query_with_default_parameter.json b/kompendium-core/src/test/resources/query_with_default_parameter.json index 3e1dc3754..ebc370a70 100644 --- a/kompendium-core/src/test/resources/query_with_default_parameter.json +++ b/kompendium-core/src/test/resources/query_with_default_parameter.json @@ -88,6 +88,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/regex_string.json b/kompendium-core/src/test/resources/regex_string.json index 41bcd3396..c1265c20b 100644 --- a/kompendium-core/src/test/resources/regex_string.json +++ b/kompendium-core/src/test/resources/regex_string.json @@ -58,6 +58,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/required_param.json b/kompendium-core/src/test/resources/required_param.json index 3ca03d47e..de5cb302d 100644 --- a/kompendium-core/src/test/resources/required_param.json +++ b/kompendium-core/src/test/resources/required_param.json @@ -67,6 +67,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/response_list.json b/kompendium-core/src/test/resources/response_list.json index 233be4722..3c34c6aee 100644 --- a/kompendium-core/src/test/resources/response_list.json +++ b/kompendium-core/src/test/resources/response_list.json @@ -80,6 +80,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/root_route.json b/kompendium-core/src/test/resources/root_route.json index d3532a565..897fe155b 100644 --- a/kompendium-core/src/test/resources/root_route.json +++ b/kompendium-core/src/test/resources/root_route.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/sealed_interface_response.json b/kompendium-core/src/test/resources/sealed_interface_response.json index 29fd80ed3..6be4c4285 100644 --- a/kompendium-core/src/test/resources/sealed_interface_response.json +++ b/kompendium-core/src/test/resources/sealed_interface_response.json @@ -62,6 +62,45 @@ "b" ], "type": "object" + }, + { + "properties": { + "c": { + "anyOf": [ + { + "properties": { + "a": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "a" + ], + "type": "object" + }, + { + "properties": { + "b": { + "format": "float", + "type": "number" + } + }, + "required": [ + "b" + ], + "type": "object" + }, + { + "$ref": "#/components/schemas/InsaneJamma" + } + ] + } + }, + "required": [ + "c" + ], + "type": "object" } ] } @@ -74,6 +113,47 @@ } }, "components": { + "schemas": { + "InsaneJamma": { + "properties": { + "c": { + "anyOf": [ + { + "properties": { + "a": { + "format": "int32", + "type": "integer" + } + }, + "required": [ + "a" + ], + "type": "object" + }, + { + "properties": { + "b": { + "format": "float", + "type": "number" + } + }, + "required": [ + "b" + ], + "type": "object" + }, + { + "$ref": "#/components/schemas/InsaneJamma" + } + ] + } + }, + "required": [ + "c" + ], + "type": "object" + } + }, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/simple_recursive.json b/kompendium-core/src/test/resources/simple_recursive.json new file mode 100644 index 000000000..b67fcdd3f --- /dev/null +++ b/kompendium-core/src/test/resources/simple_recursive.json @@ -0,0 +1,123 @@ +{ + "openapi": "3.0.3", + "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": { + "/test/simple_recursive": { + "get": { + "tags": [], + "summary": "Simple recursive example", + "description": "Pretty neato!", + "parameters": [], + "responses": { + "200": { + "description": "A successful endeavor", + "content": { + "application/json": { + "schema": { + "properties": { + "description": { + "type": "string" + }, + "mode": { + "enum": [ + "NULLABLE", + "REQUIRED", + "REPEATED" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "subColumns": { + "items": { + "$ref": "#/components/schemas/ColumnSchema" + }, + "type": "array" + }, + "type": { + "type": "string" + } + }, + "required": [ + "name", + "type", + "description", + "mode" + ], + "type": "object" + } + } + } + } + }, + "deprecated": false + } + } + }, + "components": { + "schemas": { + "ColumnSchema": { + "properties": { + "description": { + "type": "string" + }, + "mode": { + "enum": [ + "NULLABLE", + "REQUIRED", + "REPEATED" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "subColumns": { + "items": { + "$ref": "#/components/schemas/ColumnSchema" + }, + "type": "array" + }, + "type": { + "type": "string" + } + }, + "required": [ + "name", + "type", + "description", + "mode" + ], + "type": "object" + } + }, + "securitySchemes": {} + }, + "security": [], + "tags": [] +} diff --git a/kompendium-core/src/test/resources/trailing_slash.json b/kompendium-core/src/test/resources/trailing_slash.json index b3944e861..3ec8075eb 100644 --- a/kompendium-core/src/test/resources/trailing_slash.json +++ b/kompendium-core/src/test/resources/trailing_slash.json @@ -77,6 +77,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/undeclared_field.json b/kompendium-core/src/test/resources/undeclared_field.json index 7c5ca3538..be6b1ce2e 100644 --- a/kompendium-core/src/test/resources/undeclared_field.json +++ b/kompendium-core/src/test/resources/undeclared_field.json @@ -64,6 +64,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/test/resources/unique_array.json b/kompendium-core/src/test/resources/unique_array.json index 64c7aaacd..51e67341f 100644 --- a/kompendium-core/src/test/resources/unique_array.json +++ b/kompendium-core/src/test/resources/unique_array.json @@ -62,6 +62,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt b/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt index 5f1017b4a..d5a19a0ca 100644 --- a/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt +++ b/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestModels.kt @@ -4,6 +4,7 @@ import io.bkbn.kompendium.annotations.Field import io.bkbn.kompendium.annotations.FreeFormObject import io.bkbn.kompendium.annotations.Param import io.bkbn.kompendium.annotations.ParamType +import io.bkbn.kompendium.annotations.Referenced import io.bkbn.kompendium.annotations.UndeclaredField import io.bkbn.kompendium.annotations.constraint.Format import io.bkbn.kompendium.annotations.constraint.MaxItems @@ -198,7 +199,9 @@ sealed interface SlammaJamma data class OneJamma(val a: Int) : SlammaJamma data class AnothaJamma(val b: Float) : SlammaJamma -//data class InsaneJamma(val c: SlammaJamma) : SlammaJamma // 👀 + +@Referenced +data class InsaneJamma(val c: SlammaJamma) : SlammaJamma sealed interface Flibbity @@ -216,3 +219,18 @@ data class Mysterious(val nowYouSeeMe: String) data class HeaderNameTest( @Param(type = ParamType.HEADER) val `X-UserEmail`: String ) + +enum class ColumnMode { + NULLABLE, + REQUIRED, + REPEATED +} + +@Referenced +data class ColumnSchema( + val name: String, + val type: String, + val description: String, + val mode: ColumnMode, + val subColumns: List = emptyList() +) diff --git a/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestResponseInfo.kt b/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestResponseInfo.kt index d9763ad88..4451d59bc 100644 --- a/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestResponseInfo.kt +++ b/kompendium-core/src/testFixtures/kotlin/io/bkbn/kompendium/core/fixtures/TestResponseInfo.kt @@ -2,8 +2,6 @@ package io.bkbn.kompendium.core.fixtures import io.bkbn.kompendium.core.metadata.ExceptionInfo import io.bkbn.kompendium.core.metadata.ParameterExample -import io.bkbn.kompendium.core.metadata.method.PostInfo -import io.bkbn.kompendium.core.metadata.method.PutInfo import io.bkbn.kompendium.core.metadata.RequestInfo import io.bkbn.kompendium.core.metadata.ResponseInfo import io.bkbn.kompendium.core.metadata.method.DeleteInfo @@ -11,6 +9,8 @@ import io.bkbn.kompendium.core.metadata.method.GetInfo import io.bkbn.kompendium.core.metadata.method.HeadInfo import io.bkbn.kompendium.core.metadata.method.OptionsInfo import io.bkbn.kompendium.core.metadata.method.PatchInfo +import io.bkbn.kompendium.core.metadata.method.PostInfo +import io.bkbn.kompendium.core.metadata.method.PutInfo import io.ktor.http.HttpStatusCode import kotlin.reflect.typeOf @@ -169,6 +169,12 @@ object TestResponseInfo { responseInfo = simpleOkResponse() ) + val simpleRecursive = GetInfo( + summary = "Simple recursive example", + description = "Pretty neato!", + responseInfo = simpleOkResponse() + ) + val minMaxInt = GetInfo( summary = "Constrained int field", description = "Cool stuff", diff --git a/kompendium-locations/src/test/resources/notarized_delete_nested_location.json b/kompendium-locations/src/test/resources/notarized_delete_nested_location.json index e746d9c53..f1b934990 100644 --- a/kompendium-locations/src/test/resources/notarized_delete_nested_location.json +++ b/kompendium-locations/src/test/resources/notarized_delete_nested_location.json @@ -76,6 +76,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_delete_simple_location.json b/kompendium-locations/src/test/resources/notarized_delete_simple_location.json index 85cc87104..e46e06ec2 100644 --- a/kompendium-locations/src/test/resources/notarized_delete_simple_location.json +++ b/kompendium-locations/src/test/resources/notarized_delete_simple_location.json @@ -67,6 +67,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_get_nested_location.json b/kompendium-locations/src/test/resources/notarized_get_nested_location.json index 48a1b3ff8..4ea378ba4 100644 --- a/kompendium-locations/src/test/resources/notarized_get_nested_location.json +++ b/kompendium-locations/src/test/resources/notarized_get_nested_location.json @@ -76,6 +76,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_get_simple_location.json b/kompendium-locations/src/test/resources/notarized_get_simple_location.json index 5ae6eb0df..487540c48 100644 --- a/kompendium-locations/src/test/resources/notarized_get_simple_location.json +++ b/kompendium-locations/src/test/resources/notarized_get_simple_location.json @@ -67,6 +67,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_post_nested_location.json b/kompendium-locations/src/test/resources/notarized_post_nested_location.json index e3f3897f2..183c5e7d0 100644 --- a/kompendium-locations/src/test/resources/notarized_post_nested_location.json +++ b/kompendium-locations/src/test/resources/notarized_post_nested_location.json @@ -95,6 +95,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_post_simple_location.json b/kompendium-locations/src/test/resources/notarized_post_simple_location.json index d8dab1467..1be3e3911 100644 --- a/kompendium-locations/src/test/resources/notarized_post_simple_location.json +++ b/kompendium-locations/src/test/resources/notarized_post_simple_location.json @@ -86,6 +86,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_put_nested_location.json b/kompendium-locations/src/test/resources/notarized_put_nested_location.json index 3447431e7..5b1fca574 100644 --- a/kompendium-locations/src/test/resources/notarized_put_nested_location.json +++ b/kompendium-locations/src/test/resources/notarized_put_nested_location.json @@ -95,6 +95,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-locations/src/test/resources/notarized_put_simple_location.json b/kompendium-locations/src/test/resources/notarized_put_simple_location.json index f2e141fc8..bdc0ea73a 100644 --- a/kompendium-locations/src/test/resources/notarized_put_simple_location.json +++ b/kompendium-locations/src/test/resources/notarized_put_simple_location.json @@ -86,6 +86,7 @@ } }, "components": { + "schemas": {}, "securitySchemes": {} }, "security": [], diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/component/Components.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/component/Components.kt index 4bf432a63..f8fc07e50 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/component/Components.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/component/Components.kt @@ -1,9 +1,11 @@ package io.bkbn.kompendium.oas.component +import io.bkbn.kompendium.oas.schema.ComponentSchema import io.bkbn.kompendium.oas.security.SecuritySchema import kotlinx.serialization.Serializable @Serializable data class Components( + val schemas: MutableMap = mutableMapOf(), val securitySchemes: MutableMap = mutableMapOf() ) diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ComponentSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ComponentSchema.kt index 80a7f04b8..df9fa5bfd 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ComponentSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ComponentSchema.kt @@ -20,6 +20,8 @@ sealed interface ComponentSchema { is FormattedSchema -> this.copy(default = default) is ObjectSchema -> this.copy(default = default) is SimpleSchema -> this.copy(default = default) + is ReferencedSchema -> this.copy(default = default) + is FreeFormSchema -> this.copy(default = default) else -> error("Compiler bug??") } @@ -31,6 +33,8 @@ sealed interface ComponentSchema { is FormattedSchema -> this.copy(description = description) is ObjectSchema -> this.copy(description = description) is SimpleSchema -> this.copy(description = description) + is ReferencedSchema -> this.copy(description = description) + is FreeFormSchema -> this.copy(description = description) else -> error("Compiler bug??") } } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FreeFormSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FreeFormSchema.kt index 8e5bbb5ff..4f4ae4012 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FreeFormSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FreeFormSchema.kt @@ -8,9 +8,10 @@ data class FreeFormSchema( override val nullable: Boolean? = null, // constraints val minProperties: Int? = null, - val maxProperties: Int? = null + val maxProperties: Int? = null, + override val default: @Contextual Any? = null, + override val description: String? = null, ) : TypedSchema { val additionalProperties: Boolean = true override val type: String = "object" - override val default: @Contextual Any? = null } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ReferencedSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ReferencedSchema.kt new file mode 100644 index 000000000..0ed9fb3aa --- /dev/null +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ReferencedSchema.kt @@ -0,0 +1,11 @@ +package io.bkbn.kompendium.oas.schema + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable +data class ReferencedSchema( + val `$ref`: String, + override val default: @Contextual Any? = null, + override val description: String? = null +) : ComponentSchema diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt index 6580ea5fd..8c4ddac78 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt @@ -8,6 +8,7 @@ import io.bkbn.kompendium.oas.schema.EnumSchema import io.bkbn.kompendium.oas.schema.FormattedSchema import io.bkbn.kompendium.oas.schema.FreeFormSchema import io.bkbn.kompendium.oas.schema.ObjectSchema +import io.bkbn.kompendium.oas.schema.ReferencedSchema import io.bkbn.kompendium.oas.schema.SimpleSchema import io.bkbn.kompendium.oas.security.ApiKeyAuth import io.bkbn.kompendium.oas.security.BasicAuth @@ -29,6 +30,7 @@ object KompendiumSerializersModule { subclass(DictionarySchema::class, DictionarySchema.serializer()) subclass(EnumSchema::class, EnumSchema.serializer()) subclass(FreeFormSchema::class, FreeFormSchema.serializer()) + subclass(ReferencedSchema::class, ReferencedSchema.serializer()) } polymorphic(SecuritySchema::class) { subclass(ApiKeyAuth::class, ApiKeyAuth.serializer()) diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/RecursionPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/RecursionPlayground.kt new file mode 100644 index 000000000..caacb398c --- /dev/null +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/RecursionPlayground.kt @@ -0,0 +1,97 @@ +package io.bkbn.kompendium.playground + +import io.bkbn.kompendium.annotations.Referenced +import io.bkbn.kompendium.core.Kompendium +import io.bkbn.kompendium.core.Notarized.notarizedGet +import io.bkbn.kompendium.core.metadata.ResponseInfo +import io.bkbn.kompendium.core.metadata.method.GetInfo +import io.bkbn.kompendium.core.routes.redoc +import io.bkbn.kompendium.playground.util.Util +import io.ktor.application.Application +import io.ktor.application.call +import io.ktor.application.install +import io.ktor.features.ContentNegotiation +import io.ktor.http.HttpStatusCode +import io.ktor.response.respond +import io.ktor.routing.route +import io.ktor.routing.routing +import io.ktor.serialization.json +import io.ktor.server.engine.embeddedServer +import io.ktor.server.netty.Netty +import kotlinx.serialization.Serializable + +enum class ColumnMode { + NULLABLE, + REQUIRED, + REPEATED +} + +@Referenced // Indicates that Kompendium should store this class as a $ref component. +@Serializable +data class ColumnSchema( + val name: String, + val type: String, + val description: String, + val mode: ColumnMode, + val subColumns: List = emptyList() +) + +sealed interface RecursiveSlammaJamma + +@Serializable +data class OneJamma(val a: Int) : RecursiveSlammaJamma + +@Serializable +data class AnothaJamma(val b: Float) : RecursiveSlammaJamma + +@Referenced +@Serializable +data class InsaneJamma(val c: RecursiveSlammaJamma) : RecursiveSlammaJamma + +fun main() { + embeddedServer( + Netty, + port = 8081, + module = Application::mainModule + ).start(wait = true) +} + +private fun Application.mainModule() { + install(ContentNegotiation) { + json(json = Util.kotlinxConfig) + } + install(Kompendium) { + spec = Util.baseSpec + } + routing { + redoc(pageTitle = "Recursive API Docs") + notarizedGet( + GetInfo( + summary = "Its recursive", + description = "This is how we do it!", + responseInfo = ResponseInfo( + status = HttpStatusCode.OK, + description = "This means everything went as expected!", + ), + tags = setOf("Simple") + ) + ) { + call.respond(HttpStatusCode.OK, "Nice!") + } + route("cmon_and_slam") { + notarizedGet( + GetInfo( + summary = "Its recursive", + description = "This is how we do it!", + responseInfo = ResponseInfo( + status = HttpStatusCode.OK, + description = "This means everything went as expected!", + ), + tags = setOf("Simple") + ) + ) { + call.respond(HttpStatusCode.OK, "Nice!") + } + } + } +}