Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
6ba3617e32 | |||
c32c91829b | |||
b021935b10 | |||
3d99bf35fd | |||
c5f8ace5d2 |
24
CHANGELOG.md
24
CHANGELOG.md
@ -1,5 +1,29 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [1.7.0] - August 14th, 2021
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added ability to inject an emergency `UndeclaredField` in the event of certain polymorphic serializers and such
|
||||||
|
|
||||||
|
## [1.6.0] - August 12th, 2021
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Ability to add custom type schema overrides for edge case types.
|
||||||
|
|
||||||
|
## [1.5.1] - August 12th, 2021
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Fixed bug where polymorphic types were not being rendered correctly when part of collections and maps
|
||||||
|
|
||||||
|
## [1.5.0] - July 25th, 2021
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Added support for BigInteger and BigDecimal in response types
|
||||||
|
|
||||||
## [1.4.0] - July 22nd, 2021
|
## [1.4.0] - July 22nd, 2021
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
34
README.md
34
README.md
@ -96,9 +96,21 @@ The intended purpose of `KompendiumField` is to offer field level overrides such
|
|||||||
The purpose of `KompendiumParam` is to provide supplemental information needed to properly assign the type of parameter
|
The purpose of `KompendiumParam` is to provide supplemental information needed to properly assign the type of parameter
|
||||||
(cookie, header, query, path) as well as other parameter-level metadata.
|
(cookie, header, query, path) as well as other parameter-level metadata.
|
||||||
|
|
||||||
|
### Undeclared Field
|
||||||
|
|
||||||
|
There is also a final `UndeclaredField` annotation. This should be used only in an absolutely emergency. This annotation
|
||||||
|
will allow you to inject a _single_ undeclared field that will be included as part of the schema.
|
||||||
|
|
||||||
|
Due to limitations in using repeated annotations, this can only be used once per class
|
||||||
|
|
||||||
|
This is a complete hack, and is included for odd scenarios like kotlinx serialization polymorphic adapters that expect a
|
||||||
|
`type` field in order to perform their analysis.
|
||||||
|
|
||||||
|
Use this _only_ when **all** else fails
|
||||||
|
|
||||||
### Polymorphism
|
### Polymorphism
|
||||||
|
|
||||||
Out of the box, Kompendium has support for sealed classes. At runtime, it will build a mapping of all available sub-classes
|
Speaking of polymorphism... out of the box, Kompendium has support for sealed classes and interfaces. At runtime, it will build a mapping of all available sub-classes
|
||||||
and build a spec that takes `anyOf` the implementations. This is currently a weak point of the entire library, and
|
and build a spec that takes `anyOf` the implementations. This is currently a weak point of the entire library, and
|
||||||
suggestions on better implementations are welcome 🤠
|
suggestions on better implementations are welcome 🤠
|
||||||
|
|
||||||
@ -216,6 +228,25 @@ routing {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Custom Type Overrides
|
||||||
|
|
||||||
|
Kompendium does its best to analyze types and to generate an OpenAPI format accordingly. However, there are certain
|
||||||
|
classes that just don't play nice with the standard reflection analysis that Kompendium performs.
|
||||||
|
Should you encounter a data type that Kompendium cannot comprehend, you will need to
|
||||||
|
add it explicitly. For example, adding the Joda Time `DateTime` object would be as simple as the following
|
||||||
|
|
||||||
|
```kotlin
|
||||||
|
Kompendium.addCustomTypeSchema(DateTime::class, FormatSchema("date-time", "string"))
|
||||||
|
```
|
||||||
|
|
||||||
|
Since `Kompendium` is an object, this needs to be declared once, ahead of the actual API instantiation. This way, this
|
||||||
|
type override can be cached ahead of reflection. Kompendium will then match all instances of this type and return the
|
||||||
|
specified schema.
|
||||||
|
|
||||||
|
So how do you know a type can and cannot be inferred? The safe bet is that it can be. So go ahead and give it a shot.
|
||||||
|
However, in the very odd scenario (almost always having to do with date/time libraries 😤) where it can't, you can rest
|
||||||
|
safely knowing that you have the option to inject a custom override should you need to.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
### Kompendium as a singleton
|
### Kompendium as a singleton
|
||||||
@ -234,7 +265,6 @@ should have. There are several outstanding features that have been added to the
|
|||||||
|
|
||||||
- AsyncAPI Integration
|
- AsyncAPI Integration
|
||||||
- Field Validation
|
- Field Validation
|
||||||
- MavenCentral Release
|
|
||||||
|
|
||||||
If you have a feature that you would like to see implemented that is not on this list, or discover a 🐞, please open
|
If you have a feature that you would like to see implemented that is not on this list, or discover a 🐞, please open
|
||||||
an issue [here](https://github.com/bkbnio/kompendium/issues/new)
|
an issue [here](https://github.com/bkbnio/kompendium/issues/new)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Kompendium
|
# Kompendium
|
||||||
project.version=1.4.0
|
project.version=1.7.0
|
||||||
# Kotlin
|
# Kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
# Gradle
|
# Gradle
|
||||||
|
@ -4,8 +4,10 @@ import io.bkbn.kompendium.models.meta.ErrorMap
|
|||||||
import io.bkbn.kompendium.models.meta.SchemaMap
|
import io.bkbn.kompendium.models.meta.SchemaMap
|
||||||
import io.bkbn.kompendium.models.oas.OpenApiSpec
|
import io.bkbn.kompendium.models.oas.OpenApiSpec
|
||||||
import io.bkbn.kompendium.models.oas.OpenApiSpecInfo
|
import io.bkbn.kompendium.models.oas.OpenApiSpecInfo
|
||||||
|
import io.bkbn.kompendium.models.oas.TypedSchema
|
||||||
import io.bkbn.kompendium.path.CorePathCalculator
|
import io.bkbn.kompendium.path.CorePathCalculator
|
||||||
import io.bkbn.kompendium.path.PathCalculator
|
import io.bkbn.kompendium.path.PathCalculator
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains all state for the Kompendium library
|
* Maintains all state for the Kompendium library
|
||||||
@ -31,4 +33,8 @@ object Kompendium {
|
|||||||
)
|
)
|
||||||
cache = emptyMap()
|
cache = emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addCustomTypeSchema(clazz: KClass<*>, schema: TypedSchema) {
|
||||||
|
cache = cache.plus(clazz.simpleName!! to schema)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,23 +49,8 @@ object KompendiumPreFlight {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun addToCache(paramType: KType, requestType: KType, responseType: KType) {
|
fun addToCache(paramType: KType, requestType: KType, responseType: KType) {
|
||||||
gatherSubTypes(requestType).forEach {
|
Kompendium.cache = Kontent.generateKontent(requestType, Kompendium.cache)
|
||||||
Kompendium.cache = Kontent.generateKontent(it, Kompendium.cache)
|
Kompendium.cache = Kontent.generateKontent(responseType, Kompendium.cache)
|
||||||
}
|
|
||||||
gatherSubTypes(responseType).forEach {
|
|
||||||
Kompendium.cache = Kontent.generateKontent(it, Kompendium.cache)
|
|
||||||
}
|
|
||||||
Kompendium.cache = Kontent.generateParameterKontent(paramType, Kompendium.cache)
|
Kompendium.cache = Kontent.generateParameterKontent(paramType, Kompendium.cache)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun gatherSubTypes(type: KType): List<KType> {
|
|
||||||
val classifier = type.classifier as KClass<*>
|
|
||||||
return if (classifier.isSealed) {
|
|
||||||
classifier.sealedSubclasses.map {
|
|
||||||
it.createType(type.arguments)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
listOf(type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.bkbn.kompendium
|
package io.bkbn.kompendium
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.annotations.UndeclaredField
|
||||||
import io.bkbn.kompendium.models.meta.SchemaMap
|
import io.bkbn.kompendium.models.meta.SchemaMap
|
||||||
import io.bkbn.kompendium.models.oas.AnyOfReferencedSchema
|
import io.bkbn.kompendium.models.oas.AnyOfReferencedSchema
|
||||||
import io.bkbn.kompendium.models.oas.ArraySchema
|
import io.bkbn.kompendium.models.oas.ArraySchema
|
||||||
@ -7,6 +8,7 @@ import io.bkbn.kompendium.models.oas.DictionarySchema
|
|||||||
import io.bkbn.kompendium.models.oas.EnumSchema
|
import io.bkbn.kompendium.models.oas.EnumSchema
|
||||||
import io.bkbn.kompendium.models.oas.FormatSchema
|
import io.bkbn.kompendium.models.oas.FormatSchema
|
||||||
import io.bkbn.kompendium.models.oas.ObjectSchema
|
import io.bkbn.kompendium.models.oas.ObjectSchema
|
||||||
|
import io.bkbn.kompendium.models.oas.OpenApiSpecComponentSchema
|
||||||
import io.bkbn.kompendium.models.oas.ReferencedSchema
|
import io.bkbn.kompendium.models.oas.ReferencedSchema
|
||||||
import io.bkbn.kompendium.models.oas.SimpleSchema
|
import io.bkbn.kompendium.models.oas.SimpleSchema
|
||||||
import io.bkbn.kompendium.util.Helpers.COMPONENT_SLUG
|
import io.bkbn.kompendium.util.Helpers.COMPONENT_SLUG
|
||||||
@ -23,6 +25,8 @@ import kotlin.reflect.full.memberProperties
|
|||||||
import kotlin.reflect.jvm.javaField
|
import kotlin.reflect.jvm.javaField
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for generating the schema map that is used to power all object references across the API Spec.
|
* Responsible for generating the schema map that is used to power all object references across the API Spec.
|
||||||
@ -55,7 +59,22 @@ object Kontent {
|
|||||||
type: KType,
|
type: KType,
|
||||||
cache: SchemaMap = emptyMap()
|
cache: SchemaMap = emptyMap()
|
||||||
): SchemaMap {
|
): SchemaMap {
|
||||||
return generateKTypeKontent(type, cache)
|
var newCache = cache
|
||||||
|
gatherSubTypes(type).forEach {
|
||||||
|
newCache = generateKTypeKontent(it, newCache)
|
||||||
|
}
|
||||||
|
return newCache
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun gatherSubTypes(type: KType): List<KType> {
|
||||||
|
val classifier = type.classifier as KClass<*>
|
||||||
|
return if (classifier.isSealed) {
|
||||||
|
classifier.sealedSubclasses.map {
|
||||||
|
it.createType(type.arguments)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
listOf(type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,6 +125,8 @@ object Kontent {
|
|||||||
String::class -> cache.plus(clazz.simpleName!! to SimpleSchema("string"))
|
String::class -> cache.plus(clazz.simpleName!! to SimpleSchema("string"))
|
||||||
Boolean::class -> cache.plus(clazz.simpleName!! to SimpleSchema("boolean"))
|
Boolean::class -> cache.plus(clazz.simpleName!! to SimpleSchema("boolean"))
|
||||||
UUID::class -> cache.plus(clazz.simpleName!! to FormatSchema("uuid", "string"))
|
UUID::class -> cache.plus(clazz.simpleName!! to FormatSchema("uuid", "string"))
|
||||||
|
BigDecimal::class -> cache.plus(clazz.simpleName!! to FormatSchema("double", "number"))
|
||||||
|
BigInteger::class -> cache.plus(clazz.simpleName!! to FormatSchema("int64", "integer"))
|
||||||
else -> when {
|
else -> when {
|
||||||
clazz.isSubclassOf(Collection::class) -> handleCollectionType(type, clazz, cache)
|
clazz.isSubclassOf(Collection::class) -> handleCollectionType(type, clazz, cache)
|
||||||
clazz.isSubclassOf(Enum::class) -> handleEnumType(clazz, cache)
|
clazz.isSubclassOf(Enum::class) -> handleEnumType(clazz, cache)
|
||||||
@ -185,8 +206,14 @@ object Kontent {
|
|||||||
}
|
}
|
||||||
Pair(prop.name, propSchema)
|
Pair(prop.name, propSchema)
|
||||||
}
|
}
|
||||||
|
logger.debug("Looking for undeclared fields")
|
||||||
|
val undeclaredFieldMap = clazz.annotations.filterIsInstance<UndeclaredField>().associate {
|
||||||
|
val undeclaredType = it.clazz.createType()
|
||||||
|
newCache = generateKontent(undeclaredType, newCache)
|
||||||
|
it.field to ReferencedSchema(undeclaredType.getReferenceSlug())
|
||||||
|
}
|
||||||
logger.debug("$slug contains $fieldMap")
|
logger.debug("$slug contains $fieldMap")
|
||||||
val schema = ObjectSchema(fieldMap)
|
val schema = ObjectSchema(fieldMap.plus(undeclaredFieldMap))
|
||||||
logger.debug("$slug schema: $schema")
|
logger.debug("$slug schema: $schema")
|
||||||
newCache.plus(slug to schema)
|
newCache.plus(slug to schema)
|
||||||
}
|
}
|
||||||
@ -216,11 +243,20 @@ object Kontent {
|
|||||||
if (keyType?.classifier != String::class) {
|
if (keyType?.classifier != String::class) {
|
||||||
error("Invalid Map $type: OpenAPI dictionaries must have keys of type String")
|
error("Invalid Map $type: OpenAPI dictionaries must have keys of type String")
|
||||||
}
|
}
|
||||||
val valClassName = (valType?.classifier as KClass<*>).simpleName
|
val valClass = valType?.classifier as KClass<*>
|
||||||
|
val valClassName = valClass.simpleName
|
||||||
val referenceName = genericNameAdapter(type, clazz)
|
val referenceName = genericNameAdapter(type, clazz)
|
||||||
val valueReference = ReferencedSchema("$COMPONENT_SLUG/$valClassName")
|
val valueReference = when (valClass.isSealed) {
|
||||||
|
true -> {
|
||||||
|
val subTypes = gatherSubTypes(valType)
|
||||||
|
AnyOfReferencedSchema(subTypes.map {
|
||||||
|
ReferencedSchema(("$COMPONENT_SLUG/${it.getSimpleSlug()}"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
false -> ReferencedSchema("$COMPONENT_SLUG/$valClassName")
|
||||||
|
}
|
||||||
val schema = DictionarySchema(additionalProperties = valueReference)
|
val schema = DictionarySchema(additionalProperties = valueReference)
|
||||||
val updatedCache = generateKTypeKontent(valType, cache)
|
val updatedCache = generateKontent(valType, cache)
|
||||||
return updatedCache.plus(referenceName to schema)
|
return updatedCache.plus(referenceName to schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,9 +272,17 @@ object Kontent {
|
|||||||
val collectionClass = collectionType.classifier as KClass<*>
|
val collectionClass = collectionType.classifier as KClass<*>
|
||||||
logger.debug("Obtained collection class: $collectionClass")
|
logger.debug("Obtained collection class: $collectionClass")
|
||||||
val referenceName = genericNameAdapter(type, clazz)
|
val referenceName = genericNameAdapter(type, clazz)
|
||||||
val valueReference = ReferencedSchema("${COMPONENT_SLUG}/${collectionClass.simpleName}")
|
val valueReference = when (collectionClass.isSealed) {
|
||||||
|
true -> {
|
||||||
|
val subTypes = gatherSubTypes(collectionType)
|
||||||
|
AnyOfReferencedSchema(subTypes.map {
|
||||||
|
ReferencedSchema(("$COMPONENT_SLUG/${it.getSimpleSlug()}"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
false -> ReferencedSchema("${COMPONENT_SLUG}/${collectionClass.simpleName}")
|
||||||
|
}
|
||||||
val schema = ArraySchema(items = valueReference)
|
val schema = ArraySchema(items = valueReference)
|
||||||
val updatedCache = generateKTypeKontent(collectionType, cache)
|
val updatedCache = generateKontent(collectionType, cache)
|
||||||
return updatedCache.plus(referenceName to schema)
|
return updatedCache.plus(referenceName to schema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package io.bkbn.kompendium.annotations
|
||||||
|
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Repeatable
|
||||||
|
annotation class UndeclaredField(val field: String, val clazz: KClass<*>)
|
@ -32,6 +32,9 @@ import io.bkbn.kompendium.util.notarizedGetWithNotarizedException
|
|||||||
import io.bkbn.kompendium.util.notarizedPostModule
|
import io.bkbn.kompendium.util.notarizedPostModule
|
||||||
import io.bkbn.kompendium.util.notarizedPutModule
|
import io.bkbn.kompendium.util.notarizedPutModule
|
||||||
import io.bkbn.kompendium.util.pathParsingTestModule
|
import io.bkbn.kompendium.util.pathParsingTestModule
|
||||||
|
import io.bkbn.kompendium.util.polymorphicCollectionResponse
|
||||||
|
import io.bkbn.kompendium.util.polymorphicInterfaceResponse
|
||||||
|
import io.bkbn.kompendium.util.polymorphicMapResponse
|
||||||
import io.bkbn.kompendium.util.polymorphicResponse
|
import io.bkbn.kompendium.util.polymorphicResponse
|
||||||
import io.bkbn.kompendium.util.primitives
|
import io.bkbn.kompendium.util.primitives
|
||||||
import io.bkbn.kompendium.util.returnsList
|
import io.bkbn.kompendium.util.returnsList
|
||||||
@ -40,6 +43,7 @@ import io.bkbn.kompendium.util.simpleGenericResponse
|
|||||||
import io.bkbn.kompendium.util.statusPageModule
|
import io.bkbn.kompendium.util.statusPageModule
|
||||||
import io.bkbn.kompendium.util.statusPageMultiExceptions
|
import io.bkbn.kompendium.util.statusPageMultiExceptions
|
||||||
import io.bkbn.kompendium.util.trailingSlash
|
import io.bkbn.kompendium.util.trailingSlash
|
||||||
|
import io.bkbn.kompendium.util.undeclaredType
|
||||||
import io.bkbn.kompendium.util.withDefaultParameter
|
import io.bkbn.kompendium.util.withDefaultParameter
|
||||||
import io.bkbn.kompendium.util.withExamples
|
import io.bkbn.kompendium.util.withExamples
|
||||||
|
|
||||||
@ -457,6 +461,54 @@ internal class KompendiumTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Can generate a collection with polymorphic response type`() {
|
||||||
|
withTestApplication({
|
||||||
|
jacksonConfigModule()
|
||||||
|
docs()
|
||||||
|
polymorphicCollectionResponse()
|
||||||
|
}) {
|
||||||
|
// do
|
||||||
|
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
|
||||||
|
|
||||||
|
// expect
|
||||||
|
val expected = getFileSnapshot("polymorphic_list_response.json").trim()
|
||||||
|
assertEquals(expected, json, "The received json spec should match the expected content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Can generate a map with a polymorphic response type`() {
|
||||||
|
withTestApplication({
|
||||||
|
jacksonConfigModule()
|
||||||
|
docs()
|
||||||
|
polymorphicMapResponse()
|
||||||
|
}) {
|
||||||
|
// do
|
||||||
|
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
|
||||||
|
|
||||||
|
// expect
|
||||||
|
val expected = getFileSnapshot("polymorphic_map_response.json").trim()
|
||||||
|
assertEquals(expected, json, "The received json spec should match the expected content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Can generate a polymorphic response from a sealed interface`() {
|
||||||
|
withTestApplication({
|
||||||
|
jacksonConfigModule()
|
||||||
|
docs()
|
||||||
|
polymorphicInterfaceResponse()
|
||||||
|
}) {
|
||||||
|
// do
|
||||||
|
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
|
||||||
|
|
||||||
|
// expect
|
||||||
|
val expected = getFileSnapshot("sealed_interface_response.json").trim()
|
||||||
|
assertEquals(expected, json, "The received json spec should match the expected content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Can generate a response type with a generic type`() {
|
fun `Can generate a response type with a generic type`() {
|
||||||
withTestApplication({
|
withTestApplication({
|
||||||
@ -505,6 +557,22 @@ internal class KompendiumTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Can add an undeclared field`() {
|
||||||
|
withTestApplication({
|
||||||
|
kotlinxConfigModule()
|
||||||
|
docs()
|
||||||
|
undeclaredType()
|
||||||
|
}) {
|
||||||
|
// do
|
||||||
|
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
|
||||||
|
|
||||||
|
// expect
|
||||||
|
val expected = getFileSnapshot("undeclared_field.json").trim()
|
||||||
|
assertEquals(expected, json, "The received json spec should match the expected content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val oas = Kompendium.openApiSpec.copy(
|
private val oas = Kompendium.openApiSpec.copy(
|
||||||
info = OpenApiSpecInfo(
|
info = OpenApiSpecInfo(
|
||||||
title = "Test API",
|
title = "Test API",
|
||||||
|
@ -13,15 +13,7 @@ import io.bkbn.kompendium.models.oas.DictionarySchema
|
|||||||
import io.bkbn.kompendium.models.oas.FormatSchema
|
import io.bkbn.kompendium.models.oas.FormatSchema
|
||||||
import io.bkbn.kompendium.models.oas.ObjectSchema
|
import io.bkbn.kompendium.models.oas.ObjectSchema
|
||||||
import io.bkbn.kompendium.models.oas.ReferencedSchema
|
import io.bkbn.kompendium.models.oas.ReferencedSchema
|
||||||
import io.bkbn.kompendium.util.ComplexRequest
|
import io.bkbn.kompendium.util.*
|
||||||
import io.bkbn.kompendium.util.TestInvalidMap
|
|
||||||
import io.bkbn.kompendium.util.TestNestedModel
|
|
||||||
import io.bkbn.kompendium.util.TestSimpleModel
|
|
||||||
import io.bkbn.kompendium.util.TestSimpleWithEnumList
|
|
||||||
import io.bkbn.kompendium.util.TestSimpleWithEnums
|
|
||||||
import io.bkbn.kompendium.util.TestSimpleWithList
|
|
||||||
import io.bkbn.kompendium.util.TestSimpleWithMap
|
|
||||||
import io.bkbn.kompendium.util.TestWithUUID
|
|
||||||
|
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
internal class KontentTest {
|
internal class KontentTest {
|
||||||
@ -45,6 +37,18 @@ internal class KontentTest {
|
|||||||
assertEquals(FormatSchema("int64", "integer"), result["Long"])
|
assertEquals(FormatSchema("int64", "integer"), result["Long"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Object with BigDecimal and BigInteger types`() {
|
||||||
|
// do
|
||||||
|
val result = generateKontent<TestBigNumberModel>()
|
||||||
|
|
||||||
|
// expect
|
||||||
|
assertEquals(3, result.count())
|
||||||
|
assertTrue { result.containsKey(TestBigNumberModel::class.simpleName) }
|
||||||
|
assertEquals(FormatSchema("double", "number"), result["BigDecimal"])
|
||||||
|
assertEquals(FormatSchema("int64", "integer"), result["BigInteger"])
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Objects reference their base types in the cache`() {
|
fun `Objects reference their base types in the cache`() {
|
||||||
// do
|
// do
|
||||||
|
@ -4,9 +4,14 @@ import java.util.UUID
|
|||||||
import io.bkbn.kompendium.annotations.KompendiumField
|
import io.bkbn.kompendium.annotations.KompendiumField
|
||||||
import io.bkbn.kompendium.annotations.KompendiumParam
|
import io.bkbn.kompendium.annotations.KompendiumParam
|
||||||
import io.bkbn.kompendium.annotations.ParamType
|
import io.bkbn.kompendium.annotations.ParamType
|
||||||
|
import io.bkbn.kompendium.annotations.UndeclaredField
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
data class TestSimpleModel(val a: String, val b: Int)
|
data class TestSimpleModel(val a: String, val b: Int)
|
||||||
|
|
||||||
|
data class TestBigNumberModel(val a: BigDecimal, val b: BigInteger)
|
||||||
|
|
||||||
data class TestNestedModel(val inner: TestSimpleModel)
|
data class TestNestedModel(val inner: TestSimpleModel)
|
||||||
|
|
||||||
data class TestSimpleWithEnums(val a: String, val b: SimpleEnum)
|
data class TestSimpleWithEnums(val a: String, val b: SimpleEnum)
|
||||||
@ -80,7 +85,21 @@ sealed class FlibbityGibbit
|
|||||||
data class SimpleGibbit(val a: String) : FlibbityGibbit()
|
data class SimpleGibbit(val a: String) : FlibbityGibbit()
|
||||||
data class ComplexGibbit(val b: String, val c: Int) : FlibbityGibbit()
|
data class ComplexGibbit(val b: String, val c: Int) : FlibbityGibbit()
|
||||||
|
|
||||||
|
sealed interface SlammaJamma
|
||||||
|
|
||||||
|
data class OneJamma(val a: Int) : SlammaJamma
|
||||||
|
data class AnothaJamma(val b: Float) : SlammaJamma
|
||||||
|
//data class InsaneJamma(val c: SlammaJamma) : SlammaJamma // 👀
|
||||||
|
|
||||||
sealed interface Flibbity<T>
|
sealed interface Flibbity<T>
|
||||||
|
|
||||||
data class Gibbity<T>(val a: T): Flibbity<T>
|
data class Gibbity<T>(val a: T): Flibbity<T>
|
||||||
data class Bibbity<T>(val b: String, val f: T) : Flibbity<T>
|
data class Bibbity<T>(val b: String, val f: T) : Flibbity<T>
|
||||||
|
|
||||||
|
enum class Hehe {
|
||||||
|
HAHA,
|
||||||
|
HOHO
|
||||||
|
}
|
||||||
|
|
||||||
|
@UndeclaredField("nowYouDont", Hehe::class)
|
||||||
|
data class Mysterious(val nowYouSeeMe: String)
|
||||||
|
@ -285,6 +285,36 @@ fun Application.polymorphicResponse() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Application.polymorphicCollectionResponse() {
|
||||||
|
routing {
|
||||||
|
route("/test/polymorphiclist") {
|
||||||
|
notarizedGet(TestResponseInfo.polymorphicListResponse) {
|
||||||
|
call.respond(HttpStatusCode.OK, listOf(SimpleGibbit("hi")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Application.polymorphicMapResponse() {
|
||||||
|
routing {
|
||||||
|
route("/test/polymorphicmap") {
|
||||||
|
notarizedGet(TestResponseInfo.polymorphicMapResponse) {
|
||||||
|
call.respond(HttpStatusCode.OK, listOf(SimpleGibbit("hi")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Application.polymorphicInterfaceResponse() {
|
||||||
|
routing {
|
||||||
|
route("/test/polymorphicmap") {
|
||||||
|
notarizedGet(TestResponseInfo.polymorphicInterfaceResponse) {
|
||||||
|
call.respond(HttpStatusCode.OK, listOf(SimpleGibbit("hi")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Application.genericPolymorphicResponse() {
|
fun Application.genericPolymorphicResponse() {
|
||||||
routing {
|
routing {
|
||||||
route("/test/polymorphic") {
|
route("/test/polymorphic") {
|
||||||
@ -310,6 +340,16 @@ fun Application.genericPolymorphicResponseMultipleImpls() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Application.undeclaredType() {
|
||||||
|
routing {
|
||||||
|
route("/test/polymorphic") {
|
||||||
|
notarizedGet(TestResponseInfo.undeclaredResponseType) {
|
||||||
|
call.respond(HttpStatusCode.OK, Mysterious("hi"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Application.simpleGenericResponse() {
|
fun Application.simpleGenericResponse() {
|
||||||
routing {
|
routing {
|
||||||
route("/test/polymorphic") {
|
route("/test/polymorphic") {
|
||||||
|
@ -78,6 +78,21 @@ object TestResponseInfo {
|
|||||||
description = "Polymorphic response",
|
description = "Polymorphic response",
|
||||||
responseInfo = simpleOkResponse()
|
responseInfo = simpleOkResponse()
|
||||||
)
|
)
|
||||||
|
val polymorphicListResponse = GetInfo<Unit, List<FlibbityGibbit>>(
|
||||||
|
summary = "Oh so many gibbits",
|
||||||
|
description = "Polymorphic list response",
|
||||||
|
responseInfo = simpleOkResponse()
|
||||||
|
)
|
||||||
|
val polymorphicMapResponse = GetInfo<Unit, Map<String, FlibbityGibbit>>(
|
||||||
|
summary = "By gawd that's a lot of gibbits",
|
||||||
|
description = "Polymorphic list response",
|
||||||
|
responseInfo = simpleOkResponse()
|
||||||
|
)
|
||||||
|
val polymorphicInterfaceResponse = GetInfo<Unit, SlammaJamma>(
|
||||||
|
summary = "Come on and slam",
|
||||||
|
description = "and welcome to the jam",
|
||||||
|
responseInfo = simpleOkResponse()
|
||||||
|
)
|
||||||
val genericPolymorphicResponse = GetInfo<Unit, Flibbity<TestNested>>(
|
val genericPolymorphicResponse = GetInfo<Unit, Flibbity<TestNested>>(
|
||||||
summary = "More flibbity",
|
summary = "More flibbity",
|
||||||
description = "Polymorphic with generics",
|
description = "Polymorphic with generics",
|
||||||
@ -88,6 +103,11 @@ object TestResponseInfo {
|
|||||||
description = "Polymorphic with generics but like... crazier",
|
description = "Polymorphic with generics but like... crazier",
|
||||||
responseInfo = simpleOkResponse()
|
responseInfo = simpleOkResponse()
|
||||||
)
|
)
|
||||||
|
val undeclaredResponseType = GetInfo<Unit, Mysterious>(
|
||||||
|
summary = "spooky class",
|
||||||
|
description = "break this glass in scenario of emergency",
|
||||||
|
responseInfo = simpleOkResponse()
|
||||||
|
)
|
||||||
val genericResponse = GetInfo<Unit, TestGeneric<Int>>(
|
val genericResponse = GetInfo<Unit, TestGeneric<Int>>(
|
||||||
summary = "Single Generic",
|
summary = "Single Generic",
|
||||||
description = "Simple generic data class",
|
description = "Simple generic data class",
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"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/polymorphiclist" : {
|
||||||
|
"get" : {
|
||||||
|
"tags" : [ ],
|
||||||
|
"summary" : "Oh so many gibbits",
|
||||||
|
"description" : "Polymorphic list response",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"responses" : {
|
||||||
|
"200" : {
|
||||||
|
"description" : "A successful endeavor",
|
||||||
|
"content" : {
|
||||||
|
"application/json" : {
|
||||||
|
"schema" : {
|
||||||
|
"$ref" : "#/components/schemas/List-FlibbityGibbit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deprecated" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components" : {
|
||||||
|
"schemas" : {
|
||||||
|
"String" : {
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
"SimpleGibbit" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"a" : {
|
||||||
|
"$ref" : "#/components/schemas/String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"type" : "integer",
|
||||||
|
"format" : "int32"
|
||||||
|
},
|
||||||
|
"ComplexGibbit" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"b" : {
|
||||||
|
"$ref" : "#/components/schemas/String"
|
||||||
|
},
|
||||||
|
"c" : {
|
||||||
|
"$ref" : "#/components/schemas/Int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"List-FlibbityGibbit" : {
|
||||||
|
"type" : "array",
|
||||||
|
"items" : {
|
||||||
|
"anyOf" : [ {
|
||||||
|
"$ref" : "#/components/schemas/SimpleGibbit"
|
||||||
|
}, {
|
||||||
|
"$ref" : "#/components/schemas/ComplexGibbit"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securitySchemes" : { }
|
||||||
|
},
|
||||||
|
"security" : [ ],
|
||||||
|
"tags" : [ ]
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"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/polymorphicmap" : {
|
||||||
|
"get" : {
|
||||||
|
"tags" : [ ],
|
||||||
|
"summary" : "By gawd that's a lot of gibbits",
|
||||||
|
"description" : "Polymorphic list response",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"responses" : {
|
||||||
|
"200" : {
|
||||||
|
"description" : "A successful endeavor",
|
||||||
|
"content" : {
|
||||||
|
"application/json" : {
|
||||||
|
"schema" : {
|
||||||
|
"$ref" : "#/components/schemas/Map-String-FlibbityGibbit"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deprecated" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components" : {
|
||||||
|
"schemas" : {
|
||||||
|
"String" : {
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
"SimpleGibbit" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"a" : {
|
||||||
|
"$ref" : "#/components/schemas/String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"type" : "integer",
|
||||||
|
"format" : "int32"
|
||||||
|
},
|
||||||
|
"ComplexGibbit" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"b" : {
|
||||||
|
"$ref" : "#/components/schemas/String"
|
||||||
|
},
|
||||||
|
"c" : {
|
||||||
|
"$ref" : "#/components/schemas/Int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Map-String-FlibbityGibbit" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : {
|
||||||
|
"anyOf" : [ {
|
||||||
|
"$ref" : "#/components/schemas/SimpleGibbit"
|
||||||
|
}, {
|
||||||
|
"$ref" : "#/components/schemas/ComplexGibbit"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securitySchemes" : { }
|
||||||
|
},
|
||||||
|
"security" : [ ],
|
||||||
|
"tags" : [ ]
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"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/polymorphicmap" : {
|
||||||
|
"get" : {
|
||||||
|
"tags" : [ ],
|
||||||
|
"summary" : "Come on and slam",
|
||||||
|
"description" : "and welcome to the jam",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"responses" : {
|
||||||
|
"200" : {
|
||||||
|
"description" : "A successful endeavor",
|
||||||
|
"content" : {
|
||||||
|
"application/json" : {
|
||||||
|
"schema" : {
|
||||||
|
"anyOf" : [ {
|
||||||
|
"$ref" : "#/components/schemas/OneJamma"
|
||||||
|
}, {
|
||||||
|
"$ref" : "#/components/schemas/AnothaJamma"
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deprecated" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components" : {
|
||||||
|
"schemas" : {
|
||||||
|
"Int" : {
|
||||||
|
"type" : "integer",
|
||||||
|
"format" : "int32"
|
||||||
|
},
|
||||||
|
"OneJamma" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"a" : {
|
||||||
|
"$ref" : "#/components/schemas/Int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Float" : {
|
||||||
|
"type" : "number",
|
||||||
|
"format" : "float"
|
||||||
|
},
|
||||||
|
"AnothaJamma" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"b" : {
|
||||||
|
"$ref" : "#/components/schemas/Float"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securitySchemes" : { }
|
||||||
|
},
|
||||||
|
"security" : [ ],
|
||||||
|
"tags" : [ ]
|
||||||
|
}
|
73
kompendium-core/src/test/resources/undeclared_field.json
Normal file
73
kompendium-core/src/test/resources/undeclared_field.json
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"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/polymorphic" : {
|
||||||
|
"get" : {
|
||||||
|
"tags" : [ ],
|
||||||
|
"summary" : "spooky class",
|
||||||
|
"description" : "break this glass in scenario of emergency",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"responses" : {
|
||||||
|
"200" : {
|
||||||
|
"description" : "A successful endeavor",
|
||||||
|
"content" : {
|
||||||
|
"application/json" : {
|
||||||
|
"schema" : {
|
||||||
|
"$ref" : "#/components/schemas/Mysterious"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deprecated" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components" : {
|
||||||
|
"schemas" : {
|
||||||
|
"String" : {
|
||||||
|
"type" : "string"
|
||||||
|
},
|
||||||
|
"Hehe" : {
|
||||||
|
"type" : "string",
|
||||||
|
"enum" : [ "HAHA", "HOHO" ]
|
||||||
|
},
|
||||||
|
"Mysterious" : {
|
||||||
|
"type" : "object",
|
||||||
|
"properties" : {
|
||||||
|
"nowYouSeeMe" : {
|
||||||
|
"$ref" : "#/components/schemas/String"
|
||||||
|
},
|
||||||
|
"nowYouDont" : {
|
||||||
|
"$ref" : "#/components/schemas/Hehe"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"securitySchemes" : { }
|
||||||
|
},
|
||||||
|
"security" : [ ],
|
||||||
|
"tags" : [ ]
|
||||||
|
}
|
@ -18,6 +18,8 @@ dependencies {
|
|||||||
implementation(libs.bundles.ktorAuth)
|
implementation(libs.bundles.ktorAuth)
|
||||||
implementation(libs.bundles.logging)
|
implementation(libs.bundles.logging)
|
||||||
|
|
||||||
|
implementation("joda-time:joda-time:2.10.10")
|
||||||
|
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package io.bkbn.kompendium.playground
|
package io.bkbn.kompendium.playground
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.Kompendium
|
||||||
import io.bkbn.kompendium.Notarized.notarizedDelete
|
import io.bkbn.kompendium.Notarized.notarizedDelete
|
||||||
import io.bkbn.kompendium.Notarized.notarizedException
|
import io.bkbn.kompendium.Notarized.notarizedException
|
||||||
import io.bkbn.kompendium.Notarized.notarizedGet
|
import io.bkbn.kompendium.Notarized.notarizedGet
|
||||||
@ -7,7 +8,9 @@ import io.bkbn.kompendium.Notarized.notarizedPost
|
|||||||
import io.bkbn.kompendium.Notarized.notarizedPut
|
import io.bkbn.kompendium.Notarized.notarizedPut
|
||||||
import io.bkbn.kompendium.auth.KompendiumAuth.notarizedBasic
|
import io.bkbn.kompendium.auth.KompendiumAuth.notarizedBasic
|
||||||
import io.bkbn.kompendium.models.meta.ResponseInfo
|
import io.bkbn.kompendium.models.meta.ResponseInfo
|
||||||
|
import io.bkbn.kompendium.models.oas.FormatSchema
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testAuthenticatedSingleGetInfo
|
import io.bkbn.kompendium.playground.PlaygroundToC.testAuthenticatedSingleGetInfo
|
||||||
|
import io.bkbn.kompendium.playground.PlaygroundToC.testCustomOverride
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testGetWithExamples
|
import io.bkbn.kompendium.playground.PlaygroundToC.testGetWithExamples
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testIdGetInfo
|
import io.bkbn.kompendium.playground.PlaygroundToC.testIdGetInfo
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testPostWithExamples
|
import io.bkbn.kompendium.playground.PlaygroundToC.testPostWithExamples
|
||||||
@ -16,6 +19,7 @@ import io.bkbn.kompendium.playground.PlaygroundToC.testSingleGetInfo
|
|||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testSingleGetInfoWithThrowable
|
import io.bkbn.kompendium.playground.PlaygroundToC.testSingleGetInfoWithThrowable
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePostInfo
|
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePostInfo
|
||||||
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePutInfo
|
import io.bkbn.kompendium.playground.PlaygroundToC.testSinglePutInfo
|
||||||
|
import io.bkbn.kompendium.playground.PlaygroundToC.testUndeclaredFields
|
||||||
import io.bkbn.kompendium.routes.openApi
|
import io.bkbn.kompendium.routes.openApi
|
||||||
import io.bkbn.kompendium.routes.redoc
|
import io.bkbn.kompendium.routes.redoc
|
||||||
import io.bkbn.kompendium.swagger.swaggerUI
|
import io.bkbn.kompendium.swagger.swaggerUI
|
||||||
@ -36,8 +40,11 @@ import io.ktor.serialization.json
|
|||||||
import io.ktor.server.engine.embeddedServer
|
import io.ktor.server.engine.embeddedServer
|
||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
import io.ktor.webjars.Webjars
|
import io.ktor.webjars.Webjars
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
|
Kompendium.addCustomTypeSchema(DateTime::class, FormatSchema("date-time", "string"))
|
||||||
|
|
||||||
embeddedServer(
|
embeddedServer(
|
||||||
Netty,
|
Netty,
|
||||||
port = 8081,
|
port = 8081,
|
||||||
@ -114,6 +121,11 @@ fun Application.mainModule() {
|
|||||||
call.respondText { "heya" }
|
call.respondText { "heya" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
route("custom_override") {
|
||||||
|
notarizedGet(testCustomOverride) {
|
||||||
|
call.respondText { DateTime.now().toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
authenticate("basic") {
|
authenticate("basic") {
|
||||||
route("/authenticated/single") {
|
route("/authenticated/single") {
|
||||||
notarizedGet(testAuthenticatedSingleGetInfo) {
|
notarizedGet(testAuthenticatedSingleGetInfo) {
|
||||||
@ -127,5 +139,10 @@ fun Application.mainModule() {
|
|||||||
error("bad things just happened")
|
error("bad things just happened")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
route("/undeclared") {
|
||||||
|
notarizedGet(testUndeclaredFields) {
|
||||||
|
call.respondText { "hi" }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package io.bkbn.kompendium.playground
|
|||||||
import io.bkbn.kompendium.annotations.KompendiumField
|
import io.bkbn.kompendium.annotations.KompendiumField
|
||||||
import io.bkbn.kompendium.annotations.KompendiumParam
|
import io.bkbn.kompendium.annotations.KompendiumParam
|
||||||
import io.bkbn.kompendium.annotations.ParamType
|
import io.bkbn.kompendium.annotations.ParamType
|
||||||
|
import io.bkbn.kompendium.annotations.UndeclaredField
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
|
||||||
data class ExampleParams(
|
data class ExampleParams(
|
||||||
@KompendiumParam(ParamType.PATH) val id: Int,
|
@KompendiumParam(ParamType.PATH) val id: Int,
|
||||||
@ -30,3 +32,13 @@ data class ExampleResponse(val c: String)
|
|||||||
data class ExceptionResponse(val message: String)
|
data class ExceptionResponse(val message: String)
|
||||||
|
|
||||||
data class ExampleCreatedResponse(val id: Int, val c: String)
|
data class ExampleCreatedResponse(val id: Int, val c: String)
|
||||||
|
|
||||||
|
data class DateTimeWrapper(val dt: DateTime)
|
||||||
|
|
||||||
|
enum class Testerino {
|
||||||
|
First,
|
||||||
|
Second
|
||||||
|
}
|
||||||
|
|
||||||
|
@UndeclaredField("type", Testerino::class)
|
||||||
|
data class SimpleYetMysterious(val exists: Boolean)
|
||||||
|
@ -55,6 +55,15 @@ object PlaygroundToC {
|
|||||||
description = "Returns a different sample"
|
description = "Returns a different sample"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
val testCustomOverride = MethodInfo.GetInfo<Unit, DateTimeWrapper>(
|
||||||
|
summary = "custom schema test",
|
||||||
|
description = "testing",
|
||||||
|
tags = setOf("custom"),
|
||||||
|
responseInfo = ResponseInfo(
|
||||||
|
status = HttpStatusCode.OK,
|
||||||
|
description = "good tings"
|
||||||
|
)
|
||||||
|
)
|
||||||
val testSingleGetInfoWithThrowable = testSingleGetInfo.copy(
|
val testSingleGetInfoWithThrowable = testSingleGetInfo.copy(
|
||||||
summary = "Show me the error baby 🙏",
|
summary = "Show me the error baby 🙏",
|
||||||
canThrow = setOf(Exception::class)
|
canThrow = setOf(Exception::class)
|
||||||
@ -100,4 +109,13 @@ object PlaygroundToC {
|
|||||||
),
|
),
|
||||||
securitySchemes = setOf("basic")
|
securitySchemes = setOf("basic")
|
||||||
)
|
)
|
||||||
|
val testUndeclaredFields = MethodInfo.GetInfo<Unit, SimpleYetMysterious>(
|
||||||
|
summary = "Tests adding undeclared fields",
|
||||||
|
description = "vvv mysterious",
|
||||||
|
tags = setOf("mysterious"),
|
||||||
|
responseInfo = ResponseInfo(
|
||||||
|
status = HttpStatusCode.OK,
|
||||||
|
description = "good tings"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user