fix: support recursive types (#174)
This commit is contained in:
@ -12,6 +12,10 @@
|
|||||||
|
|
||||||
## Released
|
## Released
|
||||||
|
|
||||||
|
## [2.0.2] - February 4th, 2022
|
||||||
|
### Added
|
||||||
|
- `@Referenced` annotation enabling support for recursive models
|
||||||
|
|
||||||
## [2.0.1] - January 23rd, 2022
|
## [2.0.1] - January 23rd, 2022
|
||||||
|
|
||||||
### Change
|
### Change
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Kompendium
|
# Kompendium
|
||||||
project.version=2.0.1
|
project.version=2.0.2
|
||||||
# Kotlin
|
# Kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
# Gradle
|
# Gradle
|
||||||
|
@ -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
|
@ -82,6 +82,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
"basic": {
|
"basic": {
|
||||||
"type": "http",
|
"type": "http",
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
"jwt": {
|
"jwt": {
|
||||||
"bearerFormat": "JWT",
|
"bearerFormat": "JWT",
|
||||||
|
@ -82,6 +82,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {
|
"securitySchemes": {
|
||||||
"oauth": {
|
"oauth": {
|
||||||
"flows": {
|
"flows": {
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
package io.bkbn.kompendium.core
|
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.application.feature
|
||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.application
|
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(requestType, feature.config.cache)
|
||||||
feature.config.cache = Kontent.generateKontent(responseType, feature.config.cache)
|
feature.config.cache = Kontent.generateKontent(responseType, feature.config.cache)
|
||||||
feature.config.cache = Kontent.generateKontent(paramType, 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<ReferencedSchema>()
|
||||||
|
.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<ComponentSchema> = 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package io.bkbn.kompendium.core
|
|||||||
|
|
||||||
import io.bkbn.kompendium.annotations.Field
|
import io.bkbn.kompendium.annotations.Field
|
||||||
import io.bkbn.kompendium.annotations.FreeFormObject
|
import io.bkbn.kompendium.annotations.FreeFormObject
|
||||||
|
import io.bkbn.kompendium.annotations.Referenced
|
||||||
import io.bkbn.kompendium.annotations.UndeclaredField
|
import io.bkbn.kompendium.annotations.UndeclaredField
|
||||||
import io.bkbn.kompendium.annotations.constraint.Format
|
import io.bkbn.kompendium.annotations.constraint.Format
|
||||||
import io.bkbn.kompendium.annotations.constraint.MaxItems
|
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.SchemaMap
|
||||||
import io.bkbn.kompendium.core.metadata.TypeMap
|
import io.bkbn.kompendium.core.metadata.TypeMap
|
||||||
import io.bkbn.kompendium.core.util.Helpers.genericNameAdapter
|
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.getSimpleSlug
|
||||||
import io.bkbn.kompendium.core.util.Helpers.logged
|
import io.bkbn.kompendium.core.util.Helpers.logged
|
||||||
import io.bkbn.kompendium.core.util.Helpers.toNumber
|
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.FormattedSchema
|
||||||
import io.bkbn.kompendium.oas.schema.FreeFormSchema
|
import io.bkbn.kompendium.oas.schema.FreeFormSchema
|
||||||
import io.bkbn.kompendium.oas.schema.ObjectSchema
|
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.schema.SimpleSchema
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KClassifier
|
import kotlin.reflect.KClassifier
|
||||||
@ -36,6 +39,7 @@ import kotlin.reflect.KProperty1
|
|||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.reflect.full.createType
|
import kotlin.reflect.full.createType
|
||||||
import kotlin.reflect.full.findAnnotation
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
import kotlin.reflect.full.hasAnnotation
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
import kotlin.reflect.full.memberProperties
|
import kotlin.reflect.full.memberProperties
|
||||||
import kotlin.reflect.full.primaryConstructor
|
import kotlin.reflect.full.primaryConstructor
|
||||||
@ -144,6 +148,10 @@ object Kontent {
|
|||||||
false -> {
|
false -> {
|
||||||
logger.debug("$slug was not found in cache, generating now")
|
logger.debug("$slug was not found in cache, generating now")
|
||||||
var newCache = cache
|
var newCache = cache
|
||||||
|
// If referenced, add tie from simple slug to schema slug
|
||||||
|
if (clazz.hasAnnotation<Referenced>()) {
|
||||||
|
newCache = newCache.plus(type.getSimpleSlug() to ReferencedSchema(type.getReferenceSlug()))
|
||||||
|
}
|
||||||
// Grabs any type parameters mapped to the corresponding type argument(s)
|
// Grabs any type parameters mapped to the corresponding type argument(s)
|
||||||
val typeMap: TypeMap = clazz.typeParameters.zip(type.arguments).toMap()
|
val typeMap: TypeMap = clazz.typeParameters.zip(type.arguments).toMap()
|
||||||
// associates each member with a Pair of prop name to property schema
|
// 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 FreeFormSchema -> this // todo anything here?
|
||||||
is ObjectSchema -> scanForConstraints(clazz, prop)
|
is ObjectSchema -> scanForConstraints(clazz, prop)
|
||||||
is SimpleSchema -> scanForConstraints(prop)
|
is SimpleSchema -> scanForConstraints(prop)
|
||||||
|
is ReferencedSchema -> this // todo anything here?
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ArraySchema.scanForConstraints(prop: KProperty1<*, *>): ArraySchema {
|
private fun ArraySchema.scanForConstraints(prop: KProperty1<*, *>): ArraySchema {
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
package io.bkbn.kompendium.core.util
|
package io.bkbn.kompendium.core.util
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType
|
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.reflect.full.createType
|
import kotlin.reflect.full.createType
|
||||||
import kotlin.reflect.jvm.javaField
|
import kotlin.reflect.jvm.javaField
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.lang.reflect.ParameterizedType
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
object Helpers {
|
object Helpers {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(javaClass)
|
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() }
|
val UNIT_TYPE by lazy { Unit::class.createType() }
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ import io.bkbn.kompendium.core.util.requiredParameter
|
|||||||
import io.bkbn.kompendium.core.util.returnsList
|
import io.bkbn.kompendium.core.util.returnsList
|
||||||
import io.bkbn.kompendium.core.util.rootModule
|
import io.bkbn.kompendium.core.util.rootModule
|
||||||
import io.bkbn.kompendium.core.util.simpleGenericResponse
|
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.trailingSlash
|
||||||
import io.bkbn.kompendium.core.util.undeclaredType
|
import io.bkbn.kompendium.core.util.undeclaredType
|
||||||
import io.bkbn.kompendium.core.util.uniqueArray
|
import io.bkbn.kompendium.core.util.uniqueArray
|
||||||
@ -213,6 +214,9 @@ class KompendiumTest : DescribeSpec({
|
|||||||
it("Can override field values via annotation") {
|
it("Can override field values via annotation") {
|
||||||
openApiTest("field_override.json") { overrideFieldInfo() }
|
openApiTest("field_override.json") { overrideFieldInfo() }
|
||||||
}
|
}
|
||||||
|
it("Can serialize a recursive type using references") {
|
||||||
|
openApiTest("simple_recursive.json") { simpleRecursive() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
describe("Constraints") {
|
describe("Constraints") {
|
||||||
it("Can set a minimum and maximum integer value") {
|
it("Can set a minimum and maximum integer value") {
|
||||||
|
@ -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() {
|
fun Application.constrainedIntInfo() {
|
||||||
routing {
|
routing {
|
||||||
route("/test/constrained_int") {
|
route("/test/constrained_int") {
|
||||||
|
@ -119,6 +119,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -196,6 +196,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -90,6 +90,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -126,6 +126,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -114,6 +114,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -59,6 +59,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components" : {
|
"components" : {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
},
|
},
|
||||||
"security" : [ ],
|
"security" : [ ],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -113,6 +113,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -57,6 +57,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -122,6 +122,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -122,6 +122,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -115,6 +115,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -88,6 +88,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,45 @@
|
|||||||
"b"
|
"b"
|
||||||
],
|
],
|
||||||
"type": "object"
|
"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": {
|
"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": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
123
kompendium-core/src/test/resources/simple_recursive.json
Normal file
123
kompendium-core/src/test/resources/simple_recursive.json
Normal file
@ -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": []
|
||||||
|
}
|
@ -77,6 +77,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -4,6 +4,7 @@ import io.bkbn.kompendium.annotations.Field
|
|||||||
import io.bkbn.kompendium.annotations.FreeFormObject
|
import io.bkbn.kompendium.annotations.FreeFormObject
|
||||||
import io.bkbn.kompendium.annotations.Param
|
import io.bkbn.kompendium.annotations.Param
|
||||||
import io.bkbn.kompendium.annotations.ParamType
|
import io.bkbn.kompendium.annotations.ParamType
|
||||||
|
import io.bkbn.kompendium.annotations.Referenced
|
||||||
import io.bkbn.kompendium.annotations.UndeclaredField
|
import io.bkbn.kompendium.annotations.UndeclaredField
|
||||||
import io.bkbn.kompendium.annotations.constraint.Format
|
import io.bkbn.kompendium.annotations.constraint.Format
|
||||||
import io.bkbn.kompendium.annotations.constraint.MaxItems
|
import io.bkbn.kompendium.annotations.constraint.MaxItems
|
||||||
@ -198,7 +199,9 @@ sealed interface SlammaJamma
|
|||||||
|
|
||||||
data class OneJamma(val a: Int) : SlammaJamma
|
data class OneJamma(val a: Int) : SlammaJamma
|
||||||
data class AnothaJamma(val b: Float) : 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<T>
|
sealed interface Flibbity<T>
|
||||||
|
|
||||||
@ -216,3 +219,18 @@ data class Mysterious(val nowYouSeeMe: String)
|
|||||||
data class HeaderNameTest(
|
data class HeaderNameTest(
|
||||||
@Param(type = ParamType.HEADER) val `X-UserEmail`: String
|
@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<ColumnSchema> = emptyList()
|
||||||
|
)
|
||||||
|
@ -2,8 +2,6 @@ package io.bkbn.kompendium.core.fixtures
|
|||||||
|
|
||||||
import io.bkbn.kompendium.core.metadata.ExceptionInfo
|
import io.bkbn.kompendium.core.metadata.ExceptionInfo
|
||||||
import io.bkbn.kompendium.core.metadata.ParameterExample
|
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.RequestInfo
|
||||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.DeleteInfo
|
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.HeadInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.OptionsInfo
|
import io.bkbn.kompendium.core.metadata.method.OptionsInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.PatchInfo
|
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 io.ktor.http.HttpStatusCode
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
@ -169,6 +169,12 @@ object TestResponseInfo {
|
|||||||
responseInfo = simpleOkResponse()
|
responseInfo = simpleOkResponse()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val simpleRecursive = GetInfo<Unit, ColumnSchema>(
|
||||||
|
summary = "Simple recursive example",
|
||||||
|
description = "Pretty neato!",
|
||||||
|
responseInfo = simpleOkResponse()
|
||||||
|
)
|
||||||
|
|
||||||
val minMaxInt = GetInfo<Unit, MinMaxInt>(
|
val minMaxInt = GetInfo<Unit, MinMaxInt>(
|
||||||
summary = "Constrained int field",
|
summary = "Constrained int field",
|
||||||
description = "Cool stuff",
|
description = "Cool stuff",
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -76,6 +76,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -95,6 +95,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -86,6 +86,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"components": {
|
"components": {
|
||||||
|
"schemas": {},
|
||||||
"securitySchemes": {}
|
"securitySchemes": {}
|
||||||
},
|
},
|
||||||
"security": [],
|
"security": [],
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package io.bkbn.kompendium.oas.component
|
package io.bkbn.kompendium.oas.component
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||||
import io.bkbn.kompendium.oas.security.SecuritySchema
|
import io.bkbn.kompendium.oas.security.SecuritySchema
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Components(
|
data class Components(
|
||||||
|
val schemas: MutableMap<String, ComponentSchema> = mutableMapOf(),
|
||||||
val securitySchemes: MutableMap<String, SecuritySchema> = mutableMapOf()
|
val securitySchemes: MutableMap<String, SecuritySchema> = mutableMapOf()
|
||||||
)
|
)
|
||||||
|
@ -20,6 +20,8 @@ sealed interface ComponentSchema {
|
|||||||
is FormattedSchema -> this.copy(default = default)
|
is FormattedSchema -> this.copy(default = default)
|
||||||
is ObjectSchema -> this.copy(default = default)
|
is ObjectSchema -> this.copy(default = default)
|
||||||
is SimpleSchema -> 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??")
|
else -> error("Compiler bug??")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +33,8 @@ sealed interface ComponentSchema {
|
|||||||
is FormattedSchema -> this.copy(description = description)
|
is FormattedSchema -> this.copy(description = description)
|
||||||
is ObjectSchema -> this.copy(description = description)
|
is ObjectSchema -> this.copy(description = description)
|
||||||
is SimpleSchema -> 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??")
|
else -> error("Compiler bug??")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,10 @@ data class FreeFormSchema(
|
|||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// constraints
|
// constraints
|
||||||
val minProperties: Int? = null,
|
val minProperties: Int? = null,
|
||||||
val maxProperties: Int? = null
|
val maxProperties: Int? = null,
|
||||||
|
override val default: @Contextual Any? = null,
|
||||||
|
override val description: String? = null,
|
||||||
) : TypedSchema {
|
) : TypedSchema {
|
||||||
val additionalProperties: Boolean = true
|
val additionalProperties: Boolean = true
|
||||||
override val type: String = "object"
|
override val type: String = "object"
|
||||||
override val default: @Contextual Any? = null
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
@ -8,6 +8,7 @@ import io.bkbn.kompendium.oas.schema.EnumSchema
|
|||||||
import io.bkbn.kompendium.oas.schema.FormattedSchema
|
import io.bkbn.kompendium.oas.schema.FormattedSchema
|
||||||
import io.bkbn.kompendium.oas.schema.FreeFormSchema
|
import io.bkbn.kompendium.oas.schema.FreeFormSchema
|
||||||
import io.bkbn.kompendium.oas.schema.ObjectSchema
|
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.schema.SimpleSchema
|
||||||
import io.bkbn.kompendium.oas.security.ApiKeyAuth
|
import io.bkbn.kompendium.oas.security.ApiKeyAuth
|
||||||
import io.bkbn.kompendium.oas.security.BasicAuth
|
import io.bkbn.kompendium.oas.security.BasicAuth
|
||||||
@ -29,6 +30,7 @@ object KompendiumSerializersModule {
|
|||||||
subclass(DictionarySchema::class, DictionarySchema.serializer())
|
subclass(DictionarySchema::class, DictionarySchema.serializer())
|
||||||
subclass(EnumSchema::class, EnumSchema.serializer())
|
subclass(EnumSchema::class, EnumSchema.serializer())
|
||||||
subclass(FreeFormSchema::class, FreeFormSchema.serializer())
|
subclass(FreeFormSchema::class, FreeFormSchema.serializer())
|
||||||
|
subclass(ReferencedSchema::class, ReferencedSchema.serializer())
|
||||||
}
|
}
|
||||||
polymorphic(SecuritySchema::class) {
|
polymorphic(SecuritySchema::class) {
|
||||||
subclass(ApiKeyAuth::class, ApiKeyAuth.serializer())
|
subclass(ApiKeyAuth::class, ApiKeyAuth.serializer())
|
||||||
|
@ -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<ColumnSchema> = 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<Unit, ColumnSchema>(
|
||||||
|
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<Unit, RecursiveSlammaJamma>(
|
||||||
|
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!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user