feat: Multi Serialization Support (#134)
This commit is contained in:
@ -6,6 +6,8 @@
|
|||||||
- Support for including parameter examples via `MethodInfo`
|
- Support for including parameter examples via `MethodInfo`
|
||||||
|
|
||||||
### Changed
|
### 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
|
### Remove
|
||||||
|
|
||||||
|
@ -4,18 +4,18 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
// VERSIONS
|
||||||
|
val ktorVersion: String by project
|
||||||
|
val kotestVersion: String by project
|
||||||
|
|
||||||
// IMPLEMENTATION
|
// IMPLEMENTATION
|
||||||
|
|
||||||
api(projects.kompendiumOas)
|
api(projects.kompendiumOas)
|
||||||
api(projects.kompendiumAnnotations)
|
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-server-core", version = ktorVersion)
|
||||||
implementation(group = "io.ktor", name = "ktor-html-builder", 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
|
// TEST FIXTURES
|
||||||
|
|
||||||
testFixturesApi(group = "io.kotest", name = "kotest-runner-junit5-jvm", version = kotestVersion)
|
testFixturesApi(group = "io.kotest", name = "kotest-runner-junit5-jvm", version = kotestVersion)
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package io.bkbn.kompendium.core
|
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.core.metadata.SchemaMap
|
||||||
import io.bkbn.kompendium.oas.OpenApiSpec
|
import io.bkbn.kompendium.oas.OpenApiSpec
|
||||||
import io.bkbn.kompendium.oas.schema.TypedSchema
|
import io.bkbn.kompendium.oas.schema.TypedSchema
|
||||||
@ -12,7 +9,7 @@ import io.ktor.application.ApplicationFeature
|
|||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.request.path
|
import io.ktor.request.path
|
||||||
import io.ktor.response.respondText
|
import io.ktor.response.respond
|
||||||
import io.ktor.util.AttributeKey
|
import io.ktor.util.AttributeKey
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -28,13 +25,6 @@ class Kompendium(val config: Configuration) {
|
|||||||
fun addCustomTypeSchema(clazz: KClass<*>, schema: TypedSchema) {
|
fun addCustomTypeSchema(clazz: KClass<*>, schema: TypedSchema) {
|
||||||
cache = cache.plus(clazz.simpleName!! to schema)
|
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<Application, Configuration, Kompendium> {
|
companion object Feature : ApplicationFeature<Application, Configuration, Kompendium> {
|
||||||
@ -44,8 +34,7 @@ class Kompendium(val config: Configuration) {
|
|||||||
|
|
||||||
pipeline.intercept(ApplicationCallPipeline.Call) {
|
pipeline.intercept(ApplicationCallPipeline.Call) {
|
||||||
if (call.request.path() == configuration.specRoute) {
|
if (call.request.path() == configuration.specRoute) {
|
||||||
call.respondText { configuration.specToJson() }
|
call.respond(HttpStatusCode.OK, configuration.spec)
|
||||||
call.response.status(HttpStatusCode.OK)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,8 +199,13 @@ object Kontent {
|
|||||||
logger.debug("$slug contains $fieldMap")
|
logger.debug("$slug contains $fieldMap")
|
||||||
var schema = ObjectSchema(fieldMap.plus(undeclaredFieldMap))
|
var schema = ObjectSchema(fieldMap.plus(undeclaredFieldMap))
|
||||||
val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList()
|
val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList()
|
||||||
|
// todo de-dup this logic
|
||||||
if (requiredParams.isNotEmpty()) {
|
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<Field>()
|
||||||
|
?.let { field -> field.name.ifBlank { param.name!! } }
|
||||||
|
?: param.name!!
|
||||||
|
})
|
||||||
}
|
}
|
||||||
logger.debug("$slug schema: $schema")
|
logger.debug("$slug schema: $schema")
|
||||||
newCache.plus(slug to schema)
|
newCache.plus(slug to schema)
|
||||||
@ -335,8 +340,13 @@ object Kontent {
|
|||||||
val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList()
|
val requiredParams = clazz.primaryConstructor?.parameters?.filterNot { it.isOptional } ?: emptyList()
|
||||||
var schema = this
|
var schema = this
|
||||||
|
|
||||||
|
// todo dedup this
|
||||||
if (requiredParams.isNotEmpty()) {
|
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<Field>()
|
||||||
|
?.let { field -> field.name.ifBlank { param.name!! } }
|
||||||
|
?: param.name!!
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prop.returnType.isMarkedNullable) {
|
if (prop.returnType.isMarkedNullable) {
|
||||||
|
@ -72,12 +72,12 @@ object MethodParser {
|
|||||||
responseType: KType,
|
responseType: KType,
|
||||||
responseInfo: ResponseInfo<*>?,
|
responseInfo: ResponseInfo<*>?,
|
||||||
feature: Kompendium
|
feature: Kompendium
|
||||||
): Map<Int, Response<*>> = responseType.toResponseSpec(responseInfo, feature)?.let { mapOf(it) }.orEmpty()
|
): Map<Int, Response> = responseType.toResponseSpec(responseInfo, feature)?.let { mapOf(it) }.orEmpty()
|
||||||
|
|
||||||
private fun parseExceptions(
|
private fun parseExceptions(
|
||||||
exceptionInfo: Set<ExceptionInfo<*>>,
|
exceptionInfo: Set<ExceptionInfo<*>>,
|
||||||
feature: Kompendium,
|
feature: Kompendium,
|
||||||
): Map<Int, Response<*>> = exceptionInfo.associate { info ->
|
): Map<Int, Response> = exceptionInfo.associate { info ->
|
||||||
feature.config.cache = generateKontent(info.responseType, feature.config.cache)
|
feature.config.cache = generateKontent(info.responseType, feature.config.cache)
|
||||||
val response = Response(
|
val response = Response(
|
||||||
description = info.description,
|
description = info.description,
|
||||||
@ -92,13 +92,14 @@ object MethodParser {
|
|||||||
* @param requestInfo request metadata
|
* @param requestInfo request metadata
|
||||||
* @return Will return a generated [Request] if requestInfo is not null
|
* @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) {
|
when (requestInfo) {
|
||||||
null -> null
|
null -> null
|
||||||
else -> {
|
else -> {
|
||||||
Request(
|
Request(
|
||||||
description = requestInfo.description,
|
description = requestInfo.description,
|
||||||
content = feature.resolveContent(this, requestInfo.mediaTypes, requestInfo.examples) ?: mapOf(),
|
content = feature.resolveContent(this, requestInfo.mediaTypes, requestInfo.examples as Map<String, Any>)
|
||||||
|
?: mapOf(),
|
||||||
required = requestInfo.required
|
required = requestInfo.required
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -110,13 +111,13 @@ object MethodParser {
|
|||||||
* @param responseInfo response metadata
|
* @param responseInfo response metadata
|
||||||
* @return Will return a generated [Pair] if responseInfo is not null
|
* @return Will return a generated [Pair] if responseInfo is not null
|
||||||
*/
|
*/
|
||||||
private fun KType.toResponseSpec(responseInfo: ResponseInfo<*>?, feature: Kompendium): Pair<Int, Response<*>>? =
|
private fun KType.toResponseSpec(responseInfo: ResponseInfo<*>?, feature: Kompendium): Pair<Int, Response>? =
|
||||||
when (responseInfo) {
|
when (responseInfo) {
|
||||||
null -> null
|
null -> null
|
||||||
else -> {
|
else -> {
|
||||||
val specResponse = Response(
|
val specResponse = Response(
|
||||||
description = responseInfo.description,
|
description = responseInfo.description,
|
||||||
content = feature.resolveContent(this, responseInfo.mediaTypes, responseInfo.examples)
|
content = feature.resolveContent(this, responseInfo.mediaTypes, responseInfo.examples as Map<String, Any>)
|
||||||
)
|
)
|
||||||
Pair(responseInfo.status.value, specResponse)
|
Pair(responseInfo.status.value, specResponse)
|
||||||
}
|
}
|
||||||
@ -129,11 +130,11 @@ object MethodParser {
|
|||||||
* @param examples Mapping of named examples of valid bodies.
|
* @param examples Mapping of named examples of valid bodies.
|
||||||
* @return Named mapping of media types.
|
* @return Named mapping of media types.
|
||||||
*/
|
*/
|
||||||
private fun <F> Kompendium.resolveContent(
|
private fun Kompendium.resolveContent(
|
||||||
type: KType,
|
type: KType,
|
||||||
mediaTypes: List<String>,
|
mediaTypes: List<String>,
|
||||||
examples: Map<String, F>
|
examples: Map<String, Any>
|
||||||
): Map<String, MediaType<F>>? {
|
): Map<String, MediaType>? {
|
||||||
val classifier = type.classifier as KClass<*>
|
val classifier = type.classifier as KClass<*>
|
||||||
return if (type != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) {
|
return if (type != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) {
|
||||||
mediaTypes.associateWith {
|
mediaTypes.associateWith {
|
||||||
|
@ -80,7 +80,7 @@
|
|||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"org",
|
"org",
|
||||||
"amazingField",
|
"amazing_field",
|
||||||
"tables"
|
"tables"
|
||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"fieldName",
|
"field_name",
|
||||||
"b",
|
"b",
|
||||||
"aaa"
|
"aaa"
|
||||||
],
|
],
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"b"
|
"real_name"
|
||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"fieldName",
|
"field_name",
|
||||||
"b",
|
"b",
|
||||||
"aaa"
|
"aaa"
|
||||||
],
|
],
|
||||||
|
@ -82,7 +82,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"fieldName",
|
"field_name",
|
||||||
"b",
|
"b",
|
||||||
"aaa"
|
"aaa"
|
||||||
],
|
],
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("io.bkbn.sourdough.library")
|
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")
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,9 @@ import io.bkbn.kompendium.oas.component.Components
|
|||||||
import io.bkbn.kompendium.oas.info.Info
|
import io.bkbn.kompendium.oas.info.Info
|
||||||
import io.bkbn.kompendium.oas.path.Path
|
import io.bkbn.kompendium.oas.path.Path
|
||||||
import io.bkbn.kompendium.oas.server.Server
|
import io.bkbn.kompendium.oas.server.Server
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class OpenApiSpec(
|
data class OpenApiSpec(
|
||||||
val openapi: String = "3.0.3",
|
val openapi: String = "3.0.3",
|
||||||
val info: Info,
|
val info: Info,
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.common
|
package io.bkbn.kompendium.oas.common
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.serialization.UriSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ExternalDocumentation(
|
data class ExternalDocumentation(
|
||||||
|
@Serializable(with = UriSerializer::class)
|
||||||
val url: URI,
|
val url: URI,
|
||||||
val description: String?
|
val description: String?
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package io.bkbn.kompendium.oas.common
|
package io.bkbn.kompendium.oas.common
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Tag(
|
data class Tag(
|
||||||
val name: String,
|
val name: String,
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package io.bkbn.kompendium.oas.component
|
package io.bkbn.kompendium.oas.component
|
||||||
|
|
||||||
import io.bkbn.kompendium.oas.security.SecuritySchema
|
import io.bkbn.kompendium.oas.security.SecuritySchema
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Components(
|
data class Components(
|
||||||
val securitySchemes: MutableMap<String, SecuritySchema> = mutableMapOf()
|
val securitySchemes: MutableMap<String, SecuritySchema> = mutableMapOf()
|
||||||
)
|
)
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package io.bkbn.kompendium.oas.info
|
package io.bkbn.kompendium.oas.info
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.serialization.UriSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Contact(
|
data class Contact(
|
||||||
var name: String,
|
var name: String,
|
||||||
|
@Serializable(with = UriSerializer::class)
|
||||||
var url: URI? = null,
|
var url: URI? = null,
|
||||||
var email: String? = null // TODO Enforce email?
|
var email: String? = null // TODO Enforce email?
|
||||||
)
|
)
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package io.bkbn.kompendium.oas.info
|
package io.bkbn.kompendium.oas.info
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.serialization.UriSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Info(
|
data class Info(
|
||||||
var title: String? = null,
|
var title: String? = null,
|
||||||
var version: String? = null,
|
var version: String? = null,
|
||||||
var description: String? = null,
|
var description: String? = null,
|
||||||
|
@Serializable(with = UriSerializer::class)
|
||||||
var termsOfService: URI? = null,
|
var termsOfService: URI? = null,
|
||||||
var contact: Contact? = null,
|
var contact: Contact? = null,
|
||||||
var license: License? = null
|
var license: License? = null
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.info
|
package io.bkbn.kompendium.oas.info
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.serialization.UriSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class License(
|
data class License(
|
||||||
var name: String,
|
var name: String,
|
||||||
|
@Serializable(with = UriSerializer::class)
|
||||||
var url: URI? = null
|
var url: URI? = null
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,9 @@ package io.bkbn.kompendium.oas.path
|
|||||||
|
|
||||||
import io.bkbn.kompendium.oas.payload.Parameter
|
import io.bkbn.kompendium.oas.payload.Parameter
|
||||||
import io.bkbn.kompendium.oas.server.Server
|
import io.bkbn.kompendium.oas.server.Server
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Path(
|
data class Path(
|
||||||
var get: PathOperation? = null,
|
var get: PathOperation? = null,
|
||||||
var put: PathOperation? = null,
|
var put: PathOperation? = null,
|
||||||
|
@ -6,7 +6,9 @@ import io.bkbn.kompendium.oas.payload.Payload
|
|||||||
import io.bkbn.kompendium.oas.payload.Request
|
import io.bkbn.kompendium.oas.payload.Request
|
||||||
import io.bkbn.kompendium.oas.payload.Response
|
import io.bkbn.kompendium.oas.payload.Response
|
||||||
import io.bkbn.kompendium.oas.server.Server
|
import io.bkbn.kompendium.oas.server.Server
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class PathOperation(
|
data class PathOperation(
|
||||||
var tags: Set<String> = emptySet(),
|
var tags: Set<String> = emptySet(),
|
||||||
var summary: String? = null,
|
var summary: String? = null,
|
||||||
@ -14,9 +16,9 @@ data class PathOperation(
|
|||||||
var externalDocs: ExternalDocumentation? = null,
|
var externalDocs: ExternalDocumentation? = null,
|
||||||
var operationId: String? = null,
|
var operationId: String? = null,
|
||||||
var parameters: List<Parameter>? = null,
|
var parameters: List<Parameter>? = null,
|
||||||
var requestBody: Request<*>? = null,
|
var requestBody: Request? = null,
|
||||||
// TODO How to enforce `default` requirement 🧐
|
// TODO How to enforce `default` requirement 🧐
|
||||||
var responses: Map<Int, Response<*>>? = null,
|
var responses: Map<Int, Response>? = null,
|
||||||
var callbacks: Map<String, Payload>? = null, // todo what is this?
|
var callbacks: Map<String, Payload>? = null, // todo what is this?
|
||||||
var deprecated: Boolean = false,
|
var deprecated: Boolean = false,
|
||||||
var security: List<Map<String, List<String>>>? = null,
|
var security: List<Map<String, List<String>>>? = null,
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
package io.bkbn.kompendium.oas.payload
|
package io.bkbn.kompendium.oas.payload
|
||||||
|
|
||||||
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
data class MediaType<T>(
|
@Serializable
|
||||||
|
data class MediaType(
|
||||||
val schema: ComponentSchema,
|
val schema: ComponentSchema,
|
||||||
val examples: Map<String, Example<T>>? = null
|
val examples: Map<String, Example>? = null
|
||||||
) {
|
) {
|
||||||
data class Example<T>(val value: T)
|
@Serializable
|
||||||
|
data class Example(val value: @Contextual Any)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package io.bkbn.kompendium.oas.payload
|
package io.bkbn.kompendium.oas.payload
|
||||||
|
|
||||||
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Parameter(
|
data class Parameter(
|
||||||
val name: String,
|
val name: String,
|
||||||
val `in`: String, // TODO Enum? "query", "header", "path" or "cookie"
|
val `in`: String, // TODO Enum? "query", "header", "path" or "cookie"
|
||||||
@ -14,5 +17,6 @@ data class Parameter(
|
|||||||
val explode: Boolean? = null,
|
val explode: Boolean? = null,
|
||||||
val examples: Map<String, Example>? = null
|
val examples: Map<String, Example>? = null
|
||||||
) {
|
) {
|
||||||
data class Example(val value: Any)
|
@Serializable
|
||||||
|
data class Example(val value: @Contextual Any)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package io.bkbn.kompendium.oas.payload
|
package io.bkbn.kompendium.oas.payload
|
||||||
|
|
||||||
data class Request<T>(
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Request(
|
||||||
val description: String?,
|
val description: String?,
|
||||||
val content: Map<String, MediaType<T>>,
|
val content: Map<String, MediaType>,
|
||||||
val required: Boolean = false
|
val required: Boolean = false
|
||||||
) : Payload
|
) : Payload
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package io.bkbn.kompendium.oas.payload
|
package io.bkbn.kompendium.oas.payload
|
||||||
|
|
||||||
data class Response<T>(
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Response(
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
val headers: Map<String, Payload>? = null,
|
val headers: Map<String, Payload>? = null,
|
||||||
val content: Map<String, MediaType<T>>? = null,
|
val content: Map<String, MediaType>? = null,
|
||||||
val links: Map<String, Payload>? = null
|
val links: Map<String, Payload>? = null
|
||||||
) : Payload
|
) : Payload
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class AnyOfSchema(val anyOf: List<ComponentSchema>, override val description: String? = null) : ComponentSchema
|
data class AnyOfSchema(val anyOf: List<ComponentSchema>, override val description: String? = null) : ComponentSchema
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ArraySchema(
|
data class ArraySchema(
|
||||||
val items: ComponentSchema,
|
val items: ComponentSchema,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// constraints
|
// constraints
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
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 {
|
sealed interface ComponentSchema {
|
||||||
val description: String?
|
val description: String?
|
||||||
get() = null
|
get() = null
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class DictionarySchema(
|
data class DictionarySchema(
|
||||||
val additionalProperties: ComponentSchema,
|
val additionalProperties: ComponentSchema,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null
|
override val nullable: Boolean? = null
|
||||||
) : TypedSchema {
|
) : TypedSchema {
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class EnumSchema(
|
data class EnumSchema(
|
||||||
val `enum`: Set<String>,
|
val `enum`: Set<String>,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null
|
override val nullable: Boolean? = null
|
||||||
) : TypedSchema {
|
) : TypedSchema {
|
||||||
|
@ -1,15 +1,23 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
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(
|
data class FormattedSchema(
|
||||||
val format: String,
|
val format: String,
|
||||||
override val type: String,
|
override val type: String,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// Constraints
|
// Constraints
|
||||||
|
@Serializable(with = NumberSerializer::class)
|
||||||
val minimum: Number? = null,
|
val minimum: Number? = null,
|
||||||
|
@Serializable(with = NumberSerializer::class)
|
||||||
val maximum: Number? = null,
|
val maximum: Number? = null,
|
||||||
val exclusiveMinimum: Boolean? = null,
|
val exclusiveMinimum: Boolean? = null,
|
||||||
val exclusiveMaximum: Boolean? = null,
|
val exclusiveMaximum: Boolean? = null,
|
||||||
|
@Serializable(with = NumberSerializer::class)
|
||||||
val multipleOf: Number? = null,
|
val multipleOf: Number? = null,
|
||||||
) : TypedSchema
|
) : TypedSchema
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class FreeFormSchema(
|
data class FreeFormSchema(
|
||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// constraints
|
// constraints
|
||||||
@ -8,5 +12,5 @@ data class FreeFormSchema(
|
|||||||
) : TypedSchema {
|
) : TypedSchema {
|
||||||
val additionalProperties: Boolean = true
|
val additionalProperties: Boolean = true
|
||||||
override val type: String = "object"
|
override val type: String = "object"
|
||||||
override val default: Any? = null
|
override val default: @Contextual Any? = null
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ObjectSchema(
|
data class ObjectSchema(
|
||||||
val properties: Map<String, ComponentSchema>,
|
val properties: Map<String, ComponentSchema>,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// constraints
|
// constraints
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.schema
|
package io.bkbn.kompendium.oas.schema
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class SimpleSchema(
|
data class SimpleSchema(
|
||||||
override val type: String,
|
override val type: String,
|
||||||
override val default: Any? = null,
|
override val default: @Contextual Any? = null,
|
||||||
override val description: String? = null,
|
override val description: String? = null,
|
||||||
override val nullable: Boolean? = null,
|
override val nullable: Boolean? = null,
|
||||||
// Constraints
|
// Constraints
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package io.bkbn.kompendium.oas.security
|
package io.bkbn.kompendium.oas.security
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
// TODO... is there even an official ktor api auth mechanism??
|
// TODO... is there even an official ktor api auth mechanism??
|
||||||
|
|
||||||
|
@Serializable
|
||||||
@Suppress("UnusedPrivateMember")
|
@Suppress("UnusedPrivateMember")
|
||||||
class ApiKeyAuth(val `in`: ApiKeyLocation, name: String) : SecuritySchema {
|
class ApiKeyAuth(val `in`: ApiKeyLocation, val name: String) : SecuritySchema {
|
||||||
val type: String = "apiKey"
|
val type: String = "apiKey"
|
||||||
|
|
||||||
enum class ApiKeyLocation {
|
enum class ApiKeyLocation {
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package io.bkbn.kompendium.oas.security
|
package io.bkbn.kompendium.oas.security
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class BasicAuth : SecuritySchema {
|
class BasicAuth : SecuritySchema {
|
||||||
val type: String = "http"
|
val type: String = "http"
|
||||||
val scheme: String = "basic"
|
val scheme: String = "basic"
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package io.bkbn.kompendium.oas.security
|
package io.bkbn.kompendium.oas.security
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class BearerAuth(val bearerFormat: String? = null): SecuritySchema {
|
data class BearerAuth(val bearerFormat: String? = null): SecuritySchema {
|
||||||
val type: String = "http"
|
val type: String = "http"
|
||||||
val scheme: String = "bearer"
|
val scheme: String = "bearer"
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.security
|
package io.bkbn.kompendium.oas.security
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class OAuth(val description: String? = null, val flows: Flows) : SecuritySchema {
|
data class OAuth(val description: String? = null, val flows: Flows) : SecuritySchema {
|
||||||
val type: String = "oauth2"
|
val type: String = "oauth2"
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Flows(
|
data class Flows(
|
||||||
val implicit: Implicit? = null,
|
val implicit: Implicit? = null,
|
||||||
val authorizationCode: AuthorizationCode? = null,
|
val authorizationCode: AuthorizationCode? = null,
|
||||||
@ -21,12 +25,14 @@ data class OAuth(val description: String? = null, val flows: Flows) : SecuritySc
|
|||||||
get() = emptyMap()
|
get() = emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Implicit(
|
data class Implicit(
|
||||||
override val authorizationUrl: String,
|
override val authorizationUrl: String,
|
||||||
override val refreshUrl: String? = null,
|
override val refreshUrl: String? = null,
|
||||||
override val scopes: Map<String, String> = emptyMap()
|
override val scopes: Map<String, String> = emptyMap()
|
||||||
) : Flow
|
) : Flow
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class AuthorizationCode(
|
data class AuthorizationCode(
|
||||||
override val authorizationUrl: String,
|
override val authorizationUrl: String,
|
||||||
override val tokenUrl: String? = null,
|
override val tokenUrl: String? = null,
|
||||||
@ -34,12 +40,14 @@ data class OAuth(val description: String? = null, val flows: Flows) : SecuritySc
|
|||||||
override val scopes: Map<String, String> = emptyMap()
|
override val scopes: Map<String, String> = emptyMap()
|
||||||
) : Flow
|
) : Flow
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Password(
|
data class Password(
|
||||||
override val tokenUrl: String? = null,
|
override val tokenUrl: String? = null,
|
||||||
override val refreshUrl: String? = null,
|
override val refreshUrl: String? = null,
|
||||||
override val scopes: Map<String, String> = emptyMap()
|
override val scopes: Map<String, String> = emptyMap()
|
||||||
) : Flow
|
) : Flow
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ClientCredential(
|
data class ClientCredential(
|
||||||
override val tokenUrl: String? = null,
|
override val tokenUrl: String? = null,
|
||||||
override val refreshUrl: String? = null,
|
override val refreshUrl: String? = null,
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
package io.bkbn.kompendium.oas.security
|
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
|
sealed interface SecuritySchema
|
||||||
|
@ -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<T : Any> : KSerializer<T> {
|
||||||
|
override fun serialize(encoder: Encoder, value: T) {
|
||||||
|
serialize(encoder, value, value::class as KClass<T>)
|
||||||
|
}
|
||||||
|
|
||||||
|
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<T>) {
|
||||||
|
clazz.serializer().serialize(encoder, obj)
|
||||||
|
}
|
||||||
|
}
|
@ -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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<Number> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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<URI> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,12 @@
|
|||||||
package io.bkbn.kompendium.oas.server
|
package io.bkbn.kompendium.oas.server
|
||||||
|
|
||||||
|
import io.bkbn.kompendium.oas.serialization.UriSerializer
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class Server(
|
data class Server(
|
||||||
|
@Serializable(with = UriSerializer::class)
|
||||||
val url: URI,
|
val url: URI,
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
var variables: Map<String, ServerVariable>? = null
|
var variables: Map<String, ServerVariable>? = null
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package io.bkbn.kompendium.oas.server
|
package io.bkbn.kompendium.oas.server
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ServerVariable(
|
data class ServerVariable(
|
||||||
val `enum`: Set<String>, // todo enforce not empty
|
val `enum`: Set<String>, // todo enforce not empty
|
||||||
val default: String,
|
val default: String,
|
||||||
|
@ -18,10 +18,23 @@ dependencies {
|
|||||||
implementation(group = "io.ktor", name = "ktor-auth", version = ktorVersion)
|
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-auth-jwt", version = ktorVersion)
|
||||||
implementation(group = "io.ktor", name = "ktor-serialization", 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-locations", version = ktorVersion)
|
||||||
implementation(group = "io.ktor", name = "ktor-webjars", 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 = "org.jetbrains.kotlinx", "kotlinx-serialization-json", version = "1.3.1")
|
||||||
|
|
||||||
implementation(group = "joda-time", name = "joda-time", version = "2.10.13")
|
implementation(group = "joda-time", name = "joda-time", version = "2.10.13")
|
||||||
}
|
}
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
@ -7,12 +7,8 @@ import io.bkbn.kompendium.core.Notarized.notarizedGet
|
|||||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
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.AuthPlaygroundToC.simpleAuthenticatedGet
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -27,7 +23,6 @@ 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 kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
||||||
@ -44,10 +39,10 @@ fun main() {
|
|||||||
// Application Module
|
// Application Module
|
||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = AuthMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
install(Authentication) {
|
install(Authentication) {
|
||||||
// We can leverage the security config name to prevent typos
|
// 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
|
// This is where we define the available security configurations for our app
|
||||||
object SecurityConfigurations {
|
object SecurityConfigurations {
|
||||||
val basic = object : BasicAuthConfiguration {
|
val basic = object : BasicAuthConfiguration {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package io.bkbn.kompendium.playground
|
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.Field
|
||||||
import io.bkbn.kompendium.annotations.Param
|
import io.bkbn.kompendium.annotations.Param
|
||||||
import io.bkbn.kompendium.annotations.ParamType
|
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.GetInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.PostInfo
|
import io.bkbn.kompendium.core.metadata.method.PostInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
import io.bkbn.kompendium.core.routes.redoc
|
||||||
import io.bkbn.kompendium.oas.OpenApiSpec
|
import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule
|
||||||
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.BasicModels.BasicParameters
|
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.BasicRequest
|
||||||
|
import io.bkbn.kompendium.playground.BasicModels.BasicResponse
|
||||||
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleDeleteRequest
|
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleDeleteRequest
|
||||||
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExample
|
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExample
|
||||||
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExampleWithParameters
|
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simpleGetExampleWithParameters
|
||||||
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simplePostRequest
|
import io.bkbn.kompendium.playground.BasicPlaygroundToC.simplePostRequest
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -37,8 +36,9 @@ import io.ktor.routing.routing
|
|||||||
import io.ktor.serialization.json
|
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 kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
import kotlinx.serialization.json.Json
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,11 +57,11 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = BasicMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
// Configures the routes for our API
|
// Configures the routes for our API
|
||||||
routing {
|
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 {
|
object BasicModels {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BasicResponse(val c: String)
|
data class BasicResponse(val c: String)
|
||||||
@ -207,6 +175,9 @@ object BasicModels {
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class BasicRequest(
|
data class BasicRequest(
|
||||||
|
@JsonProperty("best_field")
|
||||||
|
@SerializedName("best_field")
|
||||||
|
@SerialName("best_field")
|
||||||
@Field(description = "This is a super important field!!", name = "best_field")
|
@Field(description = "This is a super important field!!", name = "best_field")
|
||||||
val d: Boolean
|
val d: Boolean
|
||||||
)
|
)
|
||||||
|
@ -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.GetInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.PostInfo
|
import io.bkbn.kompendium.core.metadata.method.PostInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
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.ConstrainedParams
|
||||||
import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedRequest
|
import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedRequest
|
||||||
import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedResponse
|
import io.bkbn.kompendium.playground.ConstrainedModels.ConstrainedResponse
|
||||||
import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedGet
|
import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedGet
|
||||||
import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedPost
|
import io.bkbn.kompendium.playground.ConstrainedPlaygroundToC.simpleConstrainedPost
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -45,7 +41,6 @@ import io.ktor.server.engine.embeddedServer
|
|||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
embeddedServer(
|
embeddedServer(
|
||||||
@ -59,11 +54,11 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = ConstrainedMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
// Configures the routes for our API
|
// Configures the routes for our API
|
||||||
routing {
|
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 {
|
object ConstrainedModels {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ConstrainedResponse(
|
data class ConstrainedResponse(
|
||||||
|
@ -6,12 +6,8 @@ import io.bkbn.kompendium.core.metadata.ExceptionInfo
|
|||||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
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.ExceptionPlaygroundToC.simpleGetExample
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -25,7 +21,6 @@ import io.ktor.server.engine.embeddedServer
|
|||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
// Application Entrypoint
|
// Application Entrypoint
|
||||||
@ -41,11 +36,11 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = ExceptionMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
install(StatusPages) {
|
install(StatusPages) {
|
||||||
exception<ExceptionModels.BadUserException> {
|
exception<ExceptionModels.BadUserException> {
|
||||||
@ -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
|
// This is a table of contents to hold all the metadata for our various API endpoints
|
||||||
object ExceptionPlaygroundToC {
|
object ExceptionPlaygroundToC {
|
||||||
private val simpleException = ExceptionInfo<ExceptionModels.ExceptionResponse>(
|
private val simpleException = ExceptionInfo<ExceptionModels.ExceptionResponse>(
|
||||||
|
@ -5,12 +5,8 @@ import io.bkbn.kompendium.core.Notarized.notarizedGet
|
|||||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
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.GenericPlaygroundToC.simpleGenericGet
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -22,7 +18,6 @@ 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 kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
||||||
@ -40,11 +35,11 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = GenericMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
redoc(pageTitle = "Simple API Docs")
|
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 {
|
object GenericModels {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Foosy<T, K>(val test: T, val otherThing: List<K>)
|
data class Foosy<T, K>(val test: T, val otherThing: List<K>)
|
||||||
|
@ -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<BasicModels.BasicRequest>()
|
||||||
|
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!"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<BasicModels.BasicRequest>()
|
||||||
|
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!"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,14 +7,10 @@ import io.bkbn.kompendium.core.metadata.ResponseInfo
|
|||||||
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
import io.bkbn.kompendium.core.routes.redoc
|
||||||
import io.bkbn.kompendium.locations.NotarizedLocation.notarizedGet
|
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.ohBoiUCrazy
|
||||||
import io.bkbn.kompendium.playground.LocationsToC.testLocation
|
import io.bkbn.kompendium.playground.LocationsToC.testLocation
|
||||||
import io.bkbn.kompendium.playground.LocationsToC.testNestLocation
|
import io.bkbn.kompendium.playground.LocationsToC.testNestLocation
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -28,7 +24,6 @@ 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 kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
||||||
@ -44,10 +39,10 @@ fun main() {
|
|||||||
|
|
||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = LocationMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
install(Locations)
|
install(Locations)
|
||||||
routing {
|
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 {
|
object LocationModels {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ExampleResponse(val c: String)
|
data class ExampleResponse(val c: String)
|
||||||
|
@ -5,12 +5,8 @@ import io.bkbn.kompendium.core.Notarized.notarizedGet
|
|||||||
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
import io.bkbn.kompendium.core.metadata.ResponseInfo
|
||||||
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
import io.bkbn.kompendium.core.metadata.method.GetInfo
|
||||||
import io.bkbn.kompendium.core.routes.redoc
|
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.PolymorphicPlaygroundToC.polymorphicExample
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
@ -22,7 +18,6 @@ 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 kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import java.net.URI
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
* Application entrypoint. Run this and head on over to `localhost:8081/docs`
|
||||||
@ -39,11 +34,11 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = PolymorphicMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
// Configures the routes for our API
|
// Configures the routes for our API
|
||||||
routing {
|
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 {
|
object PolymorphicModels {
|
||||||
sealed interface SlammaJamma
|
sealed interface SlammaJamma
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package io.bkbn.kompendium.playground
|
|||||||
|
|
||||||
import io.bkbn.kompendium.core.Kompendium
|
import io.bkbn.kompendium.core.Kompendium
|
||||||
import io.bkbn.kompendium.core.Notarized.notarizedGet
|
import io.bkbn.kompendium.core.Notarized.notarizedGet
|
||||||
|
import io.bkbn.kompendium.playground.util.Util
|
||||||
import io.bkbn.kompendium.swagger.swaggerUI
|
import io.bkbn.kompendium.swagger.swaggerUI
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
@ -32,12 +33,12 @@ fun main() {
|
|||||||
private fun Application.mainModule() {
|
private fun Application.mainModule() {
|
||||||
// Installs Simple JSON Content Negotiation
|
// Installs Simple JSON Content Negotiation
|
||||||
install(ContentNegotiation) {
|
install(ContentNegotiation) {
|
||||||
json()
|
json(json = Util.kotlinxConfig)
|
||||||
}
|
}
|
||||||
install(Webjars)
|
install(Webjars)
|
||||||
// Installs the Kompendium Plugin and sets up baseline server metadata
|
// Installs the Kompendium Plugin and sets up baseline server metadata
|
||||||
install(Kompendium) {
|
install(Kompendium) {
|
||||||
spec = BasicMetadata.spec
|
spec = Util.baseSpec
|
||||||
}
|
}
|
||||||
// Configures the routes for our API
|
// Configures the routes for our API
|
||||||
routing {
|
routing {
|
||||||
|
@ -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"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
Reference in New Issue
Block a user