From da104d0a63d25fc104e3ef19d5044e1b515eb593 Mon Sep 17 00:00:00 2001 From: Ryan Brink <5607577+unredundant@users.noreply.github.com> Date: Mon, 3 Jan 2022 21:05:30 -0500 Subject: [PATCH] feat: Multi Serialization Support (#134) --- CHANGELOG.md | 2 + kompendium-core/build.gradle.kts | 8 +-- .../io/bkbn/kompendium/core/Kompendium.kt | 15 +----- .../kotlin/io/bkbn/kompendium/core/Kontent.kt | 14 ++++- .../io/bkbn/kompendium/core/MethodParser.kt | 19 +++---- .../src/test/resources/complex_type.json | 2 +- .../test/resources/example_req_and_resp.json | 2 +- .../src/test/resources/field_override.json | 2 +- .../src/test/resources/notarized_post.json | 2 +- .../src/test/resources/notarized_put.json | 2 +- kompendium-oas/build.gradle.kts | 5 ++ .../io/bkbn/kompendium/oas/OpenApiSpec.kt | 2 + .../oas/common/ExternalDocumentation.kt | 4 ++ .../io/bkbn/kompendium/oas/common/Tag.kt | 3 ++ .../kompendium/oas/component/Components.kt | 2 + .../io/bkbn/kompendium/oas/info/Contact.kt | 4 ++ .../io/bkbn/kompendium/oas/info/Info.kt | 4 ++ .../io/bkbn/kompendium/oas/info/License.kt | 4 ++ .../io/bkbn/kompendium/oas/path/Path.kt | 2 + .../bkbn/kompendium/oas/path/PathOperation.kt | 6 ++- .../bkbn/kompendium/oas/payload/MediaType.kt | 10 ++-- .../bkbn/kompendium/oas/payload/Parameter.kt | 6 ++- .../io/bkbn/kompendium/oas/payload/Request.kt | 7 ++- .../bkbn/kompendium/oas/payload/Response.kt | 7 ++- .../bkbn/kompendium/oas/schema/AnyOfSchema.kt | 3 ++ .../bkbn/kompendium/oas/schema/ArraySchema.kt | 6 ++- .../kompendium/oas/schema/ComponentSchema.kt | 5 ++ .../kompendium/oas/schema/DictionarySchema.kt | 6 ++- .../bkbn/kompendium/oas/schema/EnumSchema.kt | 6 ++- .../kompendium/oas/schema/FormattedSchema.kt | 10 +++- .../kompendium/oas/schema/FreeFormSchema.kt | 6 ++- .../kompendium/oas/schema/ObjectSchema.kt | 6 ++- .../kompendium/oas/schema/SimpleSchema.kt | 6 ++- .../kompendium/oas/security/ApiKeyAuth.kt | 4 +- .../bkbn/kompendium/oas/security/BasicAuth.kt | 3 ++ .../kompendium/oas/security/BearerAuth.kt | 3 ++ .../io/bkbn/kompendium/oas/security/OAuth.kt | 8 +++ .../kompendium/oas/security/SecuritySchema.kt | 5 ++ .../oas/serialization/AnySerializer.kt | 27 ++++++++++ .../KompendiumSerializersModule.kt | 42 +++++++++++++++ .../oas/serialization/NumberSerializer.kt | 24 +++++++++ .../oas/serialization/UriSerializer.kt | 20 +++++++ .../io/bkbn/kompendium/oas/server/Server.kt | 4 ++ .../kompendium/oas/server/ServerVariable.kt | 3 ++ kompendium-playground/build.gradle.kts | 13 +++++ .../kompendium/playground/AuthPlayground.kt | 41 ++------------ .../kompendium/playground/BasicPlayground.kt | 53 +++++-------------- .../playground/ConstraintPlayground.kt | 41 ++------------ .../playground/ExceptionPlayground.kt | 41 ++------------ .../playground/GenericPlayground.kt | 43 ++------------- .../playground/GsonSerializationPlayground.kt | 49 +++++++++++++++++ .../JacksonSerializationPlayground.kt | 52 ++++++++++++++++++ .../playground/LocationPlayground.kt | 43 ++------------- .../playground/PolymorphicPlayground.kt | 41 ++------------ .../playground/SwaggerPlayground.kt | 5 +- .../bkbn/kompendium/playground/util/Util.kt | 48 +++++++++++++++++ 56 files changed, 475 insertions(+), 326 deletions(-) create mode 100644 kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/AnySerializer.kt create mode 100644 kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt create mode 100644 kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/NumberSerializer.kt create mode 100644 kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/UriSerializer.kt create mode 100644 kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GsonSerializationPlayground.kt create mode 100644 kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/JacksonSerializationPlayground.kt create mode 100644 kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/util/Util.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index e0b2f1eba..a7b8a4ed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ - Support for including parameter examples via `MethodInfo` ### Changed +- Kompendium now leverages the chosen API serializer. Supports Jackson, Gson and Kotlinx Serialization +- Fixed bug where overridden field names were not reflected in serialized object and required array ### Remove diff --git a/kompendium-core/build.gradle.kts b/kompendium-core/build.gradle.kts index 4de867895..1e5371440 100644 --- a/kompendium-core/build.gradle.kts +++ b/kompendium-core/build.gradle.kts @@ -4,18 +4,18 @@ plugins { } dependencies { + // VERSIONS + val ktorVersion: String by project + val kotestVersion: String by project + // IMPLEMENTATION api(projects.kompendiumOas) api(projects.kompendiumAnnotations) - val ktorVersion: String by project - val kotestVersion: String by project implementation(group = "io.ktor", name = "ktor-server-core", version = ktorVersion) implementation(group = "io.ktor", name = "ktor-html-builder", version = ktorVersion) - implementation(group = "com.fasterxml.jackson.module", name = "jackson-module-kotlin", version = "2.13.0") - // TEST FIXTURES testFixturesApi(group = "io.kotest", name = "kotest-runner-junit5-jvm", version = kotestVersion) diff --git a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kompendium.kt b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kompendium.kt index 36ba72379..19c0eba28 100644 --- a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kompendium.kt +++ b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/Kompendium.kt @@ -1,8 +1,5 @@ package io.bkbn.kompendium.core -import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature import io.bkbn.kompendium.core.metadata.SchemaMap import io.bkbn.kompendium.oas.OpenApiSpec import io.bkbn.kompendium.oas.schema.TypedSchema @@ -12,7 +9,7 @@ import io.ktor.application.ApplicationFeature import io.ktor.application.call import io.ktor.http.HttpStatusCode import io.ktor.request.path -import io.ktor.response.respondText +import io.ktor.response.respond import io.ktor.util.AttributeKey import kotlin.reflect.KClass @@ -28,13 +25,6 @@ class Kompendium(val config: Configuration) { fun addCustomTypeSchema(clazz: KClass<*>, schema: TypedSchema) { cache = cache.plus(clazz.simpleName!! to schema) } - - // TODO Add tests for this!! - var om: ObjectMapper = ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .enable(SerializationFeature.INDENT_OUTPUT) - - fun specToJson(): String = om.writeValueAsString(spec) } companion object Feature : ApplicationFeature { @@ -44,8 +34,7 @@ class Kompendium(val config: Configuration) { pipeline.intercept(ApplicationCallPipeline.Call) { if (call.request.path() == configuration.specRoute) { - call.respondText { configuration.specToJson() } - call.response.status(HttpStatusCode.OK) + call.respond(HttpStatusCode.OK, configuration.spec) } } 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 f97dfd06b..9cead6e80 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 @@ -199,8 +199,13 @@ object Kontent { logger.debug("$slug contains $fieldMap") var schema = ObjectSchema(fieldMap.plus(undeclaredFieldMap)) val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList() + // todo de-dup this logic if (requiredParams.isNotEmpty()) { - schema = schema.copy(required = requiredParams.map { it.name!! }) + schema = schema.copy(required = requiredParams.map { param -> + clazz.memberProperties.first { it.name == param.name }.findAnnotation() + ?.let { field -> field.name.ifBlank { param.name!! } } + ?: param.name!! + }) } logger.debug("$slug schema: $schema") newCache.plus(slug to schema) @@ -335,8 +340,13 @@ object Kontent { val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList() var schema = this + // todo dedup this if (requiredParams.isNotEmpty()) { - schema = schema.copy(required = requiredParams.map { it.name!! }) + schema = schema.copy(required = requiredParams.map { param -> + clazz.memberProperties.first { it.name == param.name }.findAnnotation() + ?.let { field -> field.name.ifBlank { param.name!! } } + ?: param.name!! + }) } if (prop.returnType.isMarkedNullable) { diff --git a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/MethodParser.kt b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/MethodParser.kt index ecf9591b7..9488b0d87 100644 --- a/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/MethodParser.kt +++ b/kompendium-core/src/main/kotlin/io/bkbn/kompendium/core/MethodParser.kt @@ -72,12 +72,12 @@ object MethodParser { responseType: KType, responseInfo: ResponseInfo<*>?, feature: Kompendium - ): Map> = responseType.toResponseSpec(responseInfo, feature)?.let { mapOf(it) }.orEmpty() + ): Map = responseType.toResponseSpec(responseInfo, feature)?.let { mapOf(it) }.orEmpty() private fun parseExceptions( exceptionInfo: Set>, feature: Kompendium, - ): Map> = exceptionInfo.associate { info -> + ): Map = exceptionInfo.associate { info -> feature.config.cache = generateKontent(info.responseType, feature.config.cache) val response = Response( description = info.description, @@ -92,13 +92,14 @@ object MethodParser { * @param requestInfo request metadata * @return Will return a generated [Request] if requestInfo is not null */ - private fun KType.toRequestSpec(requestInfo: RequestInfo<*>?, feature: Kompendium): Request<*>? = + private fun KType.toRequestSpec(requestInfo: RequestInfo<*>?, feature: Kompendium): Request? = when (requestInfo) { null -> null else -> { Request( description = requestInfo.description, - content = feature.resolveContent(this, requestInfo.mediaTypes, requestInfo.examples) ?: mapOf(), + content = feature.resolveContent(this, requestInfo.mediaTypes, requestInfo.examples as Map) + ?: mapOf(), required = requestInfo.required ) } @@ -110,13 +111,13 @@ object MethodParser { * @param responseInfo response metadata * @return Will return a generated [Pair] if responseInfo is not null */ - private fun KType.toResponseSpec(responseInfo: ResponseInfo<*>?, feature: Kompendium): Pair>? = + private fun KType.toResponseSpec(responseInfo: ResponseInfo<*>?, feature: Kompendium): Pair? = when (responseInfo) { null -> null else -> { val specResponse = Response( description = responseInfo.description, - content = feature.resolveContent(this, responseInfo.mediaTypes, responseInfo.examples) + content = feature.resolveContent(this, responseInfo.mediaTypes, responseInfo.examples as Map) ) Pair(responseInfo.status.value, specResponse) } @@ -129,11 +130,11 @@ object MethodParser { * @param examples Mapping of named examples of valid bodies. * @return Named mapping of media types. */ - private fun Kompendium.resolveContent( + private fun Kompendium.resolveContent( type: KType, mediaTypes: List, - examples: Map - ): Map>? { + examples: Map + ): Map? { val classifier = type.classifier as KClass<*> return if (type != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) { mediaTypes.associateWith { diff --git a/kompendium-core/src/test/resources/complex_type.json b/kompendium-core/src/test/resources/complex_type.json index 89726ce09..4b4c5f813 100644 --- a/kompendium-core/src/test/resources/complex_type.json +++ b/kompendium-core/src/test/resources/complex_type.json @@ -80,7 +80,7 @@ }, "required": [ "org", - "amazingField", + "amazing_field", "tables" ], "type": "object" 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 3346486ae..9a20d0a53 100644 --- a/kompendium-core/src/test/resources/example_req_and_resp.json +++ b/kompendium-core/src/test/resources/example_req_and_resp.json @@ -62,7 +62,7 @@ } }, "required": [ - "fieldName", + "field_name", "b", "aaa" ], diff --git a/kompendium-core/src/test/resources/field_override.json b/kompendium-core/src/test/resources/field_override.json index 984c3e14a..a69f50efa 100644 --- a/kompendium-core/src/test/resources/field_override.json +++ b/kompendium-core/src/test/resources/field_override.json @@ -45,7 +45,7 @@ } }, "required": [ - "b" + "real_name" ], "type": "object" } diff --git a/kompendium-core/src/test/resources/notarized_post.json b/kompendium-core/src/test/resources/notarized_post.json index c66447151..b5f1055a7 100644 --- a/kompendium-core/src/test/resources/notarized_post.json +++ b/kompendium-core/src/test/resources/notarized_post.json @@ -82,7 +82,7 @@ } }, "required": [ - "fieldName", + "field_name", "b", "aaa" ], diff --git a/kompendium-core/src/test/resources/notarized_put.json b/kompendium-core/src/test/resources/notarized_put.json index cd7d2f17a..55e0b4766 100644 --- a/kompendium-core/src/test/resources/notarized_put.json +++ b/kompendium-core/src/test/resources/notarized_put.json @@ -82,7 +82,7 @@ } }, "required": [ - "fieldName", + "field_name", "b", "aaa" ], diff --git a/kompendium-oas/build.gradle.kts b/kompendium-oas/build.gradle.kts index 57decae86..5ce98c10e 100644 --- a/kompendium-oas/build.gradle.kts +++ b/kompendium-oas/build.gradle.kts @@ -1,3 +1,8 @@ plugins { id("io.bkbn.sourdough.library") + kotlin("plugin.serialization") version "1.6.0" +} + +dependencies { + implementation(group = "org.jetbrains.kotlinx", "kotlinx-serialization-json", version = "1.3.1") } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/OpenApiSpec.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/OpenApiSpec.kt index c2169c508..d6cf9d92e 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/OpenApiSpec.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/OpenApiSpec.kt @@ -6,7 +6,9 @@ import io.bkbn.kompendium.oas.component.Components import io.bkbn.kompendium.oas.info.Info import io.bkbn.kompendium.oas.path.Path import io.bkbn.kompendium.oas.server.Server +import kotlinx.serialization.Serializable +@Serializable data class OpenApiSpec( val openapi: String = "3.0.3", val info: Info, diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/ExternalDocumentation.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/ExternalDocumentation.kt index 755a3e5ba..53a449cd3 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/ExternalDocumentation.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/ExternalDocumentation.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.common +import io.bkbn.kompendium.oas.serialization.UriSerializer +import kotlinx.serialization.Serializable import java.net.URI +@Serializable data class ExternalDocumentation( + @Serializable(with = UriSerializer::class) val url: URI, val description: String? ) diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/Tag.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/Tag.kt index 5cc24c5f4..1eafd98b3 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/Tag.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/common/Tag.kt @@ -1,5 +1,8 @@ package io.bkbn.kompendium.oas.common +import kotlinx.serialization.Serializable + +@Serializable data class Tag( val name: String, val description: String? = null, 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 9df9d7cab..4bf432a63 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,7 +1,9 @@ package io.bkbn.kompendium.oas.component import io.bkbn.kompendium.oas.security.SecuritySchema +import kotlinx.serialization.Serializable +@Serializable data class Components( val securitySchemes: MutableMap = mutableMapOf() ) diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Contact.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Contact.kt index 3d84d3db8..2c41e138b 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Contact.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Contact.kt @@ -1,9 +1,13 @@ package io.bkbn.kompendium.oas.info +import io.bkbn.kompendium.oas.serialization.UriSerializer +import kotlinx.serialization.Serializable import java.net.URI +@Serializable data class Contact( var name: String, + @Serializable(with = UriSerializer::class) var url: URI? = null, var email: String? = null // TODO Enforce email? ) diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Info.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Info.kt index 32b8c9307..d22cb3568 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Info.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/Info.kt @@ -1,11 +1,15 @@ package io.bkbn.kompendium.oas.info +import io.bkbn.kompendium.oas.serialization.UriSerializer +import kotlinx.serialization.Serializable import java.net.URI +@Serializable data class Info( var title: String? = null, var version: String? = null, var description: String? = null, + @Serializable(with = UriSerializer::class) var termsOfService: URI? = null, var contact: Contact? = null, var license: License? = null diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/License.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/License.kt index 37e030d7a..907d313bc 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/License.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/info/License.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.info +import io.bkbn.kompendium.oas.serialization.UriSerializer +import kotlinx.serialization.Serializable import java.net.URI +@Serializable data class License( var name: String, + @Serializable(with = UriSerializer::class) var url: URI? = null ) diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/Path.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/Path.kt index a8b0a617c..76510bf04 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/Path.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/Path.kt @@ -2,7 +2,9 @@ package io.bkbn.kompendium.oas.path import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.server.Server +import kotlinx.serialization.Serializable +@Serializable data class Path( var get: PathOperation? = null, var put: PathOperation? = null, diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/PathOperation.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/PathOperation.kt index 5bb7473bb..d55dc15b2 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/PathOperation.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/path/PathOperation.kt @@ -6,7 +6,9 @@ import io.bkbn.kompendium.oas.payload.Payload import io.bkbn.kompendium.oas.payload.Request import io.bkbn.kompendium.oas.payload.Response import io.bkbn.kompendium.oas.server.Server +import kotlinx.serialization.Serializable +@Serializable data class PathOperation( var tags: Set = emptySet(), var summary: String? = null, @@ -14,9 +16,9 @@ data class PathOperation( var externalDocs: ExternalDocumentation? = null, var operationId: String? = null, var parameters: List? = null, - var requestBody: Request<*>? = null, + var requestBody: Request? = null, // TODO How to enforce `default` requirement 🧐 - var responses: Map>? = null, + var responses: Map? = null, var callbacks: Map? = null, // todo what is this? var deprecated: Boolean = false, var security: List>>? = null, diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/MediaType.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/MediaType.kt index a4404b37f..662efada5 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/MediaType.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/MediaType.kt @@ -1,10 +1,14 @@ package io.bkbn.kompendium.oas.payload import io.bkbn.kompendium.oas.schema.ComponentSchema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable -data class MediaType( +@Serializable +data class MediaType( val schema: ComponentSchema, - val examples: Map>? = null + val examples: Map? = null ) { - data class Example(val value: T) + @Serializable + data class Example(val value: @Contextual Any) } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Parameter.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Parameter.kt index 0d216b6cb..017ca200c 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Parameter.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Parameter.kt @@ -1,7 +1,10 @@ package io.bkbn.kompendium.oas.payload import io.bkbn.kompendium.oas.schema.ComponentSchema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +@Serializable data class Parameter( val name: String, val `in`: String, // TODO Enum? "query", "header", "path" or "cookie" @@ -14,5 +17,6 @@ data class Parameter( val explode: Boolean? = null, val examples: Map? = null ) { - data class Example(val value: Any) + @Serializable + data class Example(val value: @Contextual Any) } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Request.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Request.kt index 60aae099c..a2e010e9c 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Request.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Request.kt @@ -1,7 +1,10 @@ package io.bkbn.kompendium.oas.payload -data class Request( +import kotlinx.serialization.Serializable + +@Serializable +data class Request( val description: String?, - val content: Map>, + val content: Map, val required: Boolean = false ) : Payload diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Response.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Response.kt index b6fde9b57..651cf2b96 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Response.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/payload/Response.kt @@ -1,8 +1,11 @@ package io.bkbn.kompendium.oas.payload -data class Response( +import kotlinx.serialization.Serializable + +@Serializable +data class Response( val description: String? = null, val headers: Map? = null, - val content: Map>? = null, + val content: Map? = null, val links: Map? = null ) : Payload diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/AnyOfSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/AnyOfSchema.kt index acf6b319f..3e1102348 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/AnyOfSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/AnyOfSchema.kt @@ -1,3 +1,6 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Serializable + +@Serializable data class AnyOfSchema(val anyOf: List, override val description: String? = null) : ComponentSchema diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ArraySchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ArraySchema.kt index 2aec11761..ff9587a89 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ArraySchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ArraySchema.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class ArraySchema( val items: ComponentSchema, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null, // constraints 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 ea88a3041..80a7f04b8 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 @@ -1,5 +1,10 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.JsonClassDiscriminator + +@OptIn(ExperimentalSerializationApi::class) +@JsonClassDiscriminator("component_type") // todo figure out a way to filter this sealed interface ComponentSchema { val description: String? get() = null diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/DictionarySchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/DictionarySchema.kt index f0868ce3d..a25932888 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/DictionarySchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/DictionarySchema.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class DictionarySchema( val additionalProperties: ComponentSchema, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null ) : TypedSchema { diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/EnumSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/EnumSchema.kt index 2852a8c00..abe701fff 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/EnumSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/EnumSchema.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class EnumSchema( val `enum`: Set, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null ) : TypedSchema { diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FormattedSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FormattedSchema.kt index 3aecbba53..ebcdd287f 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FormattedSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/FormattedSchema.kt @@ -1,15 +1,23 @@ package io.bkbn.kompendium.oas.schema +import io.bkbn.kompendium.oas.serialization.NumberSerializer +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class FormattedSchema( val format: String, override val type: String, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null, // Constraints + @Serializable(with = NumberSerializer::class) val minimum: Number? = null, + @Serializable(with = NumberSerializer::class) val maximum: Number? = null, val exclusiveMinimum: Boolean? = null, val exclusiveMaximum: Boolean? = null, + @Serializable(with = NumberSerializer::class) val multipleOf: Number? = null, ) : TypedSchema 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 c5e17d55f..8e5bbb5ff 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 @@ -1,5 +1,9 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class FreeFormSchema( override val nullable: Boolean? = null, // constraints @@ -8,5 +12,5 @@ data class FreeFormSchema( ) : TypedSchema { val additionalProperties: Boolean = true override val type: String = "object" - override val default: Any? = null + override val default: @Contextual Any? = null } diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ObjectSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ObjectSchema.kt index 17c02363d..9771b41ca 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ObjectSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/ObjectSchema.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class ObjectSchema( val properties: Map, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null, // constraints diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/SimpleSchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/SimpleSchema.kt index 13533c744..c0b3f7dc6 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/SimpleSchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/schema/SimpleSchema.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.schema +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable + +@Serializable data class SimpleSchema( override val type: String, - override val default: Any? = null, + override val default: @Contextual Any? = null, override val description: String? = null, override val nullable: Boolean? = null, // Constraints diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/ApiKeyAuth.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/ApiKeyAuth.kt index 64960ebd8..32c07d316 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/ApiKeyAuth.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/ApiKeyAuth.kt @@ -1,11 +1,13 @@ package io.bkbn.kompendium.oas.security +import kotlinx.serialization.Serializable import java.util.Locale // TODO... is there even an official ktor api auth mechanism?? +@Serializable @Suppress("UnusedPrivateMember") -class ApiKeyAuth(val `in`: ApiKeyLocation, name: String) : SecuritySchema { +class ApiKeyAuth(val `in`: ApiKeyLocation, val name: String) : SecuritySchema { val type: String = "apiKey" enum class ApiKeyLocation { diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BasicAuth.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BasicAuth.kt index 7d1649b75..77baa15ae 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BasicAuth.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BasicAuth.kt @@ -1,5 +1,8 @@ package io.bkbn.kompendium.oas.security +import kotlinx.serialization.Serializable + +@Serializable class BasicAuth : SecuritySchema { val type: String = "http" val scheme: String = "basic" diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BearerAuth.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BearerAuth.kt index 07427ac29..6ede93e02 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BearerAuth.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/BearerAuth.kt @@ -1,5 +1,8 @@ package io.bkbn.kompendium.oas.security +import kotlinx.serialization.Serializable + +@Serializable data class BearerAuth(val bearerFormat: String? = null): SecuritySchema { val type: String = "http" val scheme: String = "bearer" diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/OAuth.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/OAuth.kt index 3a90fbb08..ea0bc058c 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/OAuth.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/OAuth.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.security +import kotlinx.serialization.Serializable + +@Serializable data class OAuth(val description: String? = null, val flows: Flows) : SecuritySchema { val type: String = "oauth2" + @Serializable data class Flows( val implicit: Implicit? = null, val authorizationCode: AuthorizationCode? = null, @@ -21,12 +25,14 @@ data class OAuth(val description: String? = null, val flows: Flows) : SecuritySc get() = emptyMap() } + @Serializable data class Implicit( override val authorizationUrl: String, override val refreshUrl: String? = null, override val scopes: Map = emptyMap() ) : Flow + @Serializable data class AuthorizationCode( override val authorizationUrl: String, override val tokenUrl: String? = null, @@ -34,12 +40,14 @@ data class OAuth(val description: String? = null, val flows: Flows) : SecuritySc override val scopes: Map = emptyMap() ) : Flow + @Serializable data class Password( override val tokenUrl: String? = null, override val refreshUrl: String? = null, override val scopes: Map = emptyMap() ) : Flow + @Serializable data class ClientCredential( override val tokenUrl: String? = null, override val refreshUrl: String? = null, diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/SecuritySchema.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/SecuritySchema.kt index 6f1d7ddf1..e36055281 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/SecuritySchema.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/security/SecuritySchema.kt @@ -1,3 +1,8 @@ package io.bkbn.kompendium.oas.security +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.JsonClassDiscriminator + +@OptIn(ExperimentalSerializationApi::class) +@JsonClassDiscriminator("schema_type") // todo figure out a way to filter this sealed interface SecuritySchema diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/AnySerializer.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/AnySerializer.kt new file mode 100644 index 000000000..85cadeb6d --- /dev/null +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/AnySerializer.kt @@ -0,0 +1,27 @@ +package io.bkbn.kompendium.oas.serialization + +import kotlin.reflect.KClass +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.serializer + +class AnySerializer : KSerializer { + override fun serialize(encoder: Encoder, value: T) { + serialize(encoder, value, value::class as KClass) + } + + override fun deserialize(decoder: Decoder): T { + error("Abandon all hope ye who enter 💀") + } + + override val descriptor: SerialDescriptor + get() = TODO("Not yet implemented") + + @OptIn(InternalSerializationApi::class) + fun serialize(encoder: Encoder, obj: T, clazz: KClass) { + clazz.serializer().serialize(encoder, obj) + } +} 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 new file mode 100644 index 000000000..6580ea5fd --- /dev/null +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/KompendiumSerializersModule.kt @@ -0,0 +1,42 @@ +package io.bkbn.kompendium.oas.serialization + +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.SimpleSchema +import io.bkbn.kompendium.oas.security.ApiKeyAuth +import io.bkbn.kompendium.oas.security.BasicAuth +import io.bkbn.kompendium.oas.security.BearerAuth +import io.bkbn.kompendium.oas.security.OAuth +import io.bkbn.kompendium.oas.security.SecuritySchema +import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.modules.polymorphic + +object KompendiumSerializersModule { + + val module = SerializersModule { + polymorphic(ComponentSchema::class) { + subclass(SimpleSchema::class, SimpleSchema.serializer()) + subclass(FormattedSchema::class, FormattedSchema.serializer()) + subclass(ObjectSchema::class, ObjectSchema.serializer()) + subclass(AnyOfSchema::class, AnyOfSchema.serializer()) + subclass(ArraySchema::class, ArraySchema.serializer()) + subclass(DictionarySchema::class, DictionarySchema.serializer()) + subclass(EnumSchema::class, EnumSchema.serializer()) + subclass(FreeFormSchema::class, FreeFormSchema.serializer()) + } + polymorphic(SecuritySchema::class) { + subclass(ApiKeyAuth::class, ApiKeyAuth.serializer()) + subclass(BasicAuth::class, BasicAuth.serializer()) + subclass(BearerAuth::class, BearerAuth.serializer()) + subclass(OAuth::class, OAuth.serializer()) + } + contextual(Any::class, AnySerializer()) + } + +} diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/NumberSerializer.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/NumberSerializer.kt new file mode 100644 index 000000000..809bcac7e --- /dev/null +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/NumberSerializer.kt @@ -0,0 +1,24 @@ +package io.bkbn.kompendium.oas.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +object NumberSerializer : KSerializer { + override fun deserialize(decoder: Decoder): Number = try { + decoder.decodeDouble() + } catch (_: SerializationException) { + decoder.decodeInt() + } + + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Number", PrimitiveKind.DOUBLE) + + override fun serialize(encoder: Encoder, value: Number) { + encoder.encodeString(value.toString()) + } + +} diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/UriSerializer.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/UriSerializer.kt new file mode 100644 index 000000000..b5dc60c21 --- /dev/null +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/serialization/UriSerializer.kt @@ -0,0 +1,20 @@ +package io.bkbn.kompendium.oas.serialization + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import java.net.URI + +object UriSerializer : KSerializer { + override fun deserialize(decoder: Decoder): URI = URI.create(decoder.decodeString()) + + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("URI", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: URI) { + encoder.encodeString(value.toString()) + } + +} diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/Server.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/Server.kt index 423b72a88..4ed3c911b 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/Server.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/Server.kt @@ -1,8 +1,12 @@ package io.bkbn.kompendium.oas.server +import io.bkbn.kompendium.oas.serialization.UriSerializer +import kotlinx.serialization.Serializable import java.net.URI +@Serializable data class Server( + @Serializable(with = UriSerializer::class) val url: URI, val description: String? = null, var variables: Map? = null diff --git a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/ServerVariable.kt b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/ServerVariable.kt index ae1d076a0..805856021 100644 --- a/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/ServerVariable.kt +++ b/kompendium-oas/src/main/kotlin/io/bkbn/kompendium/oas/server/ServerVariable.kt @@ -1,5 +1,8 @@ package io.bkbn.kompendium.oas.server +import kotlinx.serialization.Serializable + +@Serializable data class ServerVariable( val `enum`: Set, // todo enforce not empty val default: String, diff --git a/kompendium-playground/build.gradle.kts b/kompendium-playground/build.gradle.kts index ffaed5f46..bf31bff95 100644 --- a/kompendium-playground/build.gradle.kts +++ b/kompendium-playground/build.gradle.kts @@ -18,10 +18,23 @@ dependencies { implementation(group = "io.ktor", name = "ktor-auth", version = ktorVersion) implementation(group = "io.ktor", name = "ktor-auth-jwt", version = ktorVersion) implementation(group = "io.ktor", name = "ktor-serialization", version = ktorVersion) + implementation(group = "io.ktor", name = "ktor-jackson", version = ktorVersion) + implementation(group = "io.ktor", name = "ktor-gson", version = ktorVersion) implementation(group = "io.ktor", name = "ktor-locations", version = ktorVersion) implementation(group = "io.ktor", name = "ktor-webjars", version = ktorVersion) + // Logging + implementation("org.apache.logging.log4j:log4j-api-kotlin:1.1.0") + implementation("org.apache.logging.log4j:log4j-api:2.17.0") + implementation("org.apache.logging.log4j:log4j-core:2.17.0") + implementation("org.slf4j:slf4j-api:1.7.32") + implementation("org.slf4j:slf4j-simple:1.7.32") + + implementation(group = "org.jetbrains.kotlinx", "kotlinx-serialization-json", version = "1.3.1") implementation(group = "joda-time", name = "joda-time", version = "2.10.13") } +repositories { + mavenCentral() +} diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/AuthPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/AuthPlayground.kt index 702ca4381..59a5d075d 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/AuthPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/AuthPlayground.kt @@ -7,12 +7,8 @@ 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.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.AuthPlaygroundToC.simpleAuthenticatedGet +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -27,7 +23,6 @@ import io.ktor.serialization.json import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlinx.serialization.Serializable -import java.net.URI /** * Application entrypoint. Run this and head on over to `localhost:8081/docs` @@ -44,10 +39,10 @@ fun main() { // Application Module private fun Application.mainModule() { install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } install(Kompendium) { - spec = AuthMetadata.spec + spec = Util.baseSpec } install(Authentication) { // We can leverage the security config name to prevent typos @@ -73,36 +68,6 @@ private fun Application.mainModule() { } } -object AuthMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple API with documented Authentication", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - // This is where we define the available security configurations for our app object SecurityConfigurations { val basic = object : BasicAuthConfiguration { diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/BasicPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/BasicPlayground.kt index fb0449485..b6a9a729d 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/BasicPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/BasicPlayground.kt @@ -1,5 +1,7 @@ package io.bkbn.kompendium.playground +import com.fasterxml.jackson.annotation.JsonProperty +import com.google.gson.annotations.SerializedName import io.bkbn.kompendium.annotations.Field import io.bkbn.kompendium.annotations.Param import io.bkbn.kompendium.annotations.ParamType @@ -13,18 +15,15 @@ import io.bkbn.kompendium.core.metadata.method.DeleteInfo import io.bkbn.kompendium.core.metadata.method.GetInfo import io.bkbn.kompendium.core.metadata.method.PostInfo import io.bkbn.kompendium.core.routes.redoc -import io.bkbn.kompendium.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server +import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule import io.bkbn.kompendium.playground.BasicModels.BasicParameters -import io.bkbn.kompendium.playground.BasicModels.BasicResponse import io.bkbn.kompendium.playground.BasicModels.BasicRequest +import io.bkbn.kompendium.playground.BasicModels.BasicResponse import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleDeleteRequest import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExample import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExampleWithParameters import io.bkbn.kompendium.playground.BasicPlaygroundToC.simplePostRequest +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -37,8 +36,9 @@ 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.SerialName import kotlinx.serialization.Serializable -import java.net.URI +import kotlinx.serialization.json.Json import java.util.UUID /** @@ -57,11 +57,11 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = BasicMetadata.spec + spec = Util.baseSpec } // Configures the routes for our API routing { @@ -161,38 +161,6 @@ object BasicPlaygroundToC { ) } -// Contains the root metadata for our server. This is all the stuff that is defined once -// and cannot be inferred from the Ktor application -object BasicMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo API", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - object BasicModels { @Serializable data class BasicResponse(val c: String) @@ -207,6 +175,9 @@ object BasicModels { @Serializable data class BasicRequest( + @JsonProperty("best_field") + @SerializedName("best_field") + @SerialName("best_field") @Field(description = "This is a super important field!!", name = "best_field") val d: Boolean ) diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ConstraintPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ConstraintPlayground.kt index 9aa0fb016..34bc2449c 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ConstraintPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ConstraintPlayground.kt @@ -23,16 +23,12 @@ import io.bkbn.kompendium.core.metadata.ResponseInfo import io.bkbn.kompendium.core.metadata.method.GetInfo import io.bkbn.kompendium.core.metadata.method.PostInfo import io.bkbn.kompendium.core.routes.redoc -import io.bkbn.kompendium.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedParams import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedRequest import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedResponse import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedGet import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedPost +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -45,7 +41,6 @@ import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlinx.serialization.Serializable import kotlinx.serialization.json.JsonElement -import java.net.URI fun main() { embeddedServer( @@ -59,11 +54,11 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = ConstrainedMetadata.spec + spec = Util.baseSpec } // Configures the routes for our API routing { @@ -104,36 +99,6 @@ object ConstrainedPlaygroundToC { ) } -object ConstrainedMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo API", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - object ConstrainedModels { @Serializable data class ConstrainedResponse( diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ExceptionPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ExceptionPlayground.kt index 3b05f5a28..490a90bf1 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ExceptionPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/ExceptionPlayground.kt @@ -6,12 +6,8 @@ import io.bkbn.kompendium.core.metadata.ExceptionInfo 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.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.ExceptionPlaygroundToC.simpleGetExample +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -25,7 +21,6 @@ import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlin.reflect.typeOf import kotlinx.serialization.Serializable -import java.net.URI import java.time.LocalDateTime // Application Entrypoint @@ -41,11 +36,11 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = ExceptionMetadata.spec + spec = Util.baseSpec } install(StatusPages) { exception { @@ -70,36 +65,6 @@ private fun Application.mainModule() { } } -object ExceptionMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo API with notarized exceptions", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - // This is a table of contents to hold all the metadata for our various API endpoints object ExceptionPlaygroundToC { private val simpleException = ExceptionInfo( diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GenericPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GenericPlayground.kt index 9ddbd0944..c6b1fff52 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GenericPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GenericPlayground.kt @@ -5,12 +5,8 @@ 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.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.GenericPlaygroundToC.simpleGenericGet +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -22,7 +18,6 @@ import io.ktor.serialization.json import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlinx.serialization.Serializable -import java.net.URI /** * Application entrypoint. Run this and head on over to `localhost:8081/docs` @@ -40,11 +35,11 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = GenericMetadata.spec + spec = Util.baseSpec } routing { redoc(pageTitle = "Simple API Docs") @@ -70,38 +65,6 @@ object GenericPlaygroundToC { ) } -// Contains the root metadata for our server. This is all the stuff that is defined once -// and cannot be inferred from the Ktor application -object GenericMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo API with Generic Data", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - object GenericModels { @Serializable data class Foosy(val test: T, val otherThing: List) diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GsonSerializationPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GsonSerializationPlayground.kt new file mode 100644 index 000000000..04ee780a3 --- /dev/null +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/GsonSerializationPlayground.kt @@ -0,0 +1,49 @@ +package io.bkbn.kompendium.playground + +import io.bkbn.kompendium.core.Kompendium +import io.bkbn.kompendium.core.Notarized.notarizedPost +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.gson.gson +import io.ktor.http.HttpStatusCode +import io.ktor.request.receive +import io.ktor.response.respond +import io.ktor.routing.route +import io.ktor.routing.routing +import io.ktor.server.engine.embeddedServer +import io.ktor.server.netty.Netty + +fun main() { + embeddedServer( + Netty, + port = 8081, + module = Application::mainModule + ).start(wait = true) +} + +private fun Application.mainModule() { + install(ContentNegotiation) { + gson { + setPrettyPrinting() + } + } + install(Kompendium) { + spec = Util.baseSpec + } + routing { + redoc() + route("/create") { + notarizedPost(BasicPlaygroundToC.simplePostRequest) { + val request = call.receive() + when (request.d) { + true -> call.respond(HttpStatusCode.OK, BasicModels.BasicResponse(c = "So it is true!")) + false -> call.respond(HttpStatusCode.OK, BasicModels.BasicResponse(c = "Oh, I knew it!")) + } + } + } + } +} diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/JacksonSerializationPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/JacksonSerializationPlayground.kt new file mode 100644 index 000000000..16feb5a75 --- /dev/null +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/JacksonSerializationPlayground.kt @@ -0,0 +1,52 @@ +package io.bkbn.kompendium.playground + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.SerializationFeature +import io.bkbn.kompendium.core.Kompendium +import io.bkbn.kompendium.core.Notarized.notarizedPost +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.jackson.jackson +import io.ktor.request.receive +import io.ktor.response.respond +import io.ktor.routing.route +import io.ktor.routing.routing +import io.ktor.server.engine.embeddedServer +import io.ktor.server.netty.Netty + +fun main() { + embeddedServer( + Netty, + port = 8081, + module = Application::mainModule + ).start(wait = true) +} + +private fun Application.mainModule() { + install(ContentNegotiation) { + jackson { + enable(SerializationFeature.INDENT_OUTPUT) + setSerializationInclusion(JsonInclude.Include.NON_NULL) + } + } + install(Kompendium) { + spec = Util.baseSpec + } + routing { + redoc() + route("/create") { + notarizedPost(BasicPlaygroundToC.simplePostRequest) { + val request = call.receive() + when (request.d) { + true -> call.respond(HttpStatusCode.OK, BasicModels.BasicResponse(c = "So it is true!")) + false -> call.respond(HttpStatusCode.OK, BasicModels.BasicResponse(c = "Oh, I knew it!")) + } + } + } + } +} diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/LocationPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/LocationPlayground.kt index 440ecd3b3..56d7081e5 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/LocationPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/LocationPlayground.kt @@ -7,14 +7,10 @@ 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.locations.NotarizedLocation.notarizedGet -import io.bkbn.kompendium.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.LocationsToC.ohBoiUCrazy import io.bkbn.kompendium.playground.LocationsToC.testLocation import io.bkbn.kompendium.playground.LocationsToC.testNestLocation +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -28,7 +24,6 @@ import io.ktor.serialization.json import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlinx.serialization.Serializable -import java.net.URI /** * Application entrypoint. Run this and head on over to `localhost:8081/docs` @@ -44,10 +39,10 @@ fun main() { private fun Application.mainModule() { install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } install(Kompendium) { - spec = LocationMetadata.spec + spec = Util.baseSpec } install(Locations) routing { @@ -118,38 +113,6 @@ data class TestLocations( } } -// Contains the root metadata for our server. This is all the stuff that is defined once -// and cannot be inferred from the Ktor application -object LocationMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo Leveraging Ktor Locations", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - object LocationModels { @Serializable data class ExampleResponse(val c: String) diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/PolymorphicPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/PolymorphicPlayground.kt index 0bfdd5126..1fc0f152f 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/PolymorphicPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/PolymorphicPlayground.kt @@ -5,12 +5,8 @@ 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.oas.OpenApiSpec -import io.bkbn.kompendium.oas.info.Contact -import io.bkbn.kompendium.oas.info.Info -import io.bkbn.kompendium.oas.info.License -import io.bkbn.kompendium.oas.server.Server import io.bkbn.kompendium.playground.PolymorphicPlaygroundToC.polymorphicExample +import io.bkbn.kompendium.playground.util.Util import io.ktor.application.Application import io.ktor.application.call import io.ktor.application.install @@ -22,7 +18,6 @@ import io.ktor.serialization.json import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty import kotlinx.serialization.Serializable -import java.net.URI /** * Application entrypoint. Run this and head on over to `localhost:8081/docs` @@ -39,11 +34,11 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = PolymorphicMetadata.spec + spec = Util.baseSpec } // Configures the routes for our API routing { @@ -70,36 +65,6 @@ object PolymorphicPlaygroundToC { ) } -object PolymorphicMetadata { - val spec = OpenApiSpec( - info = Info( - title = "Simple Demo API with Polymorphic Models", - version = "1.33.7", - description = "Wow isn't this cool?", - termsOfService = URI("https://example.com"), - contact = Contact( - name = "Homer Simpson", - email = "chunkylover53@aol.com", - url = URI("https://gph.is/1NPUDiM") - ), - license = License( - name = "MIT", - url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") - ) - ), - servers = mutableListOf( - Server( - url = URI("https://myawesomeapi.com"), - description = "Production instance of my API" - ), - Server( - url = URI("https://staging.myawesomeapi.com"), - description = "Where the fun stuff happens" - ) - ) - ) -} - object PolymorphicModels { sealed interface SlammaJamma diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/SwaggerPlayground.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/SwaggerPlayground.kt index 13252b63c..682ec6f8f 100644 --- a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/SwaggerPlayground.kt +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/SwaggerPlayground.kt @@ -2,6 +2,7 @@ package io.bkbn.kompendium.playground import io.bkbn.kompendium.core.Kompendium import io.bkbn.kompendium.core.Notarized.notarizedGet +import io.bkbn.kompendium.playground.util.Util import io.bkbn.kompendium.swagger.swaggerUI import io.ktor.application.Application import io.ktor.application.call @@ -32,12 +33,12 @@ fun main() { private fun Application.mainModule() { // Installs Simple JSON Content Negotiation install(ContentNegotiation) { - json() + json(json = Util.kotlinxConfig) } install(Webjars) // Installs the Kompendium Plugin and sets up baseline server metadata install(Kompendium) { - spec = BasicMetadata.spec + spec = Util.baseSpec } // Configures the routes for our API routing { diff --git a/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/util/Util.kt b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/util/Util.kt new file mode 100644 index 000000000..bc388343d --- /dev/null +++ b/kompendium-playground/src/main/kotlin/io/bkbn/kompendium/playground/util/Util.kt @@ -0,0 +1,48 @@ +package io.bkbn.kompendium.playground.util + +import io.bkbn.kompendium.oas.OpenApiSpec +import io.bkbn.kompendium.oas.info.Contact +import io.bkbn.kompendium.oas.info.Info +import io.bkbn.kompendium.oas.info.License +import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule +import io.bkbn.kompendium.oas.server.Server +import kotlinx.serialization.json.Json +import java.net.URI + +object Util { + val kotlinxConfig = Json { + classDiscriminator = "class" + serializersModule = KompendiumSerializersModule.module + prettyPrint = true + explicitNulls = false + encodeDefaults = true + } + + val baseSpec = OpenApiSpec( + info = Info( + title = "Simple Demo API", + version = "1.33.7", + description = "Wow isn't this cool?", + termsOfService = URI("https://example.com"), + contact = Contact( + name = "Homer Simpson", + email = "chunkylover53@aol.com", + url = URI("https://gph.is/1NPUDiM") + ), + license = License( + name = "MIT", + url = URI("https://github.com/bkbnio/kompendium/blob/main/LICENSE") + ) + ), + servers = mutableListOf( + Server( + url = URI("https://myawesomeapi.com"), + description = "Production instance of my API" + ), + Server( + url = URI("https://staging.myawesomeapi.com"), + description = "Where the fun stuff happens" + ) + ) + ) +}