Compare commits

...

39 Commits

Author SHA1 Message Date
884a50fc83 chore: prep for 3.14.3 release 2023-05-22 09:39:54 -04:00
588e52c9df fix: allow for request bodies to be marked as required=false (#470) 2023-05-22 09:39:04 -04:00
f49fcb2a22 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.1 (#469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-17 23:39:18 +00:00
0a9475a7ab fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.5.1 (#463)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-11 21:54:50 +00:00
f8fbb7ad25 fix(deps): update kotestversion to v5.6.2 (#462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-11 02:53:10 +00:00
f792fb5d1f fix(deps): update dependency com.google.protobuf:protobuf-java to v3.23.0 (#461)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 11:08:22 +00:00
845d1a971d fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.8.21 (#460)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 06:19:56 +00:00
9396b2ecfe chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.8.21 (#459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 03:36:01 +00:00
d74b7b3f28 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.8.21 (#458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-10 03:31:13 +00:00
e783630845 chore(deps): update dependency gradle to v8.1.1 (#457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-09 23:17:06 +00:00
d907ba004a chore: prep for 3.14.2 release 2023-05-08 11:50:45 -04:00
5c7ec4fdb4 fix: route with parameter declared via ktor function (#455) 2023-05-08 11:49:29 -04:00
097413067b chore: prep for 3.14.1 release 2023-04-28 10:59:27 -04:00
eb7360b8d2 fix: fixed generic property enrichment (#454) 2023-04-28 10:58:20 -04:00
3ec467c1d8 fix(deps): update ktor to v2.3.0 (#452)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-22 18:14:04 +00:00
152476c26e fix(deps): update dependency io.kotest:kotest-assertions-json-jvm to v5.6.1 (#451)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-18 21:15:51 +00:00
c4df4c7b2c fix(deps): update dependency io.kotest:kotest-runner-junit5-jvm to v5.6.0 (#450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-17 05:49:54 +00:00
87fa0b5602 chore(deps): update dependency gradle to v8.1 (#449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-15 17:00:27 +00:00
53c76d6037 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.22.3 (#448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-13 08:56:13 +00:00
44324ca3a4 chore: rearrange docs (#447) 2023-04-10 19:00:26 +00:00
9364fb19e4 chore: prep for 3.14.0 release 2023-04-06 15:49:07 -04:00
ca1f632665 feat: Introduce Support for Response Headers (#446) 2023-04-06 19:47:48 +00:00
9bb3184735 docs: add showcase link to readme 2023-04-03 19:44:42 -04:00
9a139b5713 chore(deps): update plugin org.jetbrains.kotlin.plugin.serialization to v1.8.20 (#440)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 10:54:36 -04:00
9861c8e258 chore(deps): update plugin org.jetbrains.kotlin.jvm to v1.8.20 (#439)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 13:10:37 +00:00
02f8ed04f2 fix(deps): update dependency dev.forst:ktor-api-key to v2.2.4 (#442)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 12:54:06 +00:00
3e23939386 fix(deps): update dependency joda-time:joda-time to v2.12.5 (#441)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 00:21:18 +00:00
d0575944db fix(deps): update dependency org.jetbrains.kotlin:kotlin-reflect to v1.8.20 (#438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 11:17:39 +00:00
ccc81c2813 fix(deps): update dependency joda-time:joda-time to v2.12.4 (#436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 10:20:45 +00:00
e8da52fd75 fix(deps): update dependency joda-time:joda-time to v2.12.3 (#435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 12:49:37 +00:00
34c14e26da fix(deps): update dependency org.slf4j:slf4j-simple to v2.0.7 (#434)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-18 01:17:47 +00:00
209b5e38a3 fix(deps): update dependency org.slf4j:slf4j-api to v2.0.7 (#433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-17 23:50:21 +00:00
902faa9471 fix(deps): update dependency io.gitlab.arturbosch.detekt:detekt-formatting to v1.22.0 (#388) 2023-03-16 12:53:15 +00:00
c7ef70a844 fix(deps): update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.5.0 (#432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 12:25:44 +00:00
f83c3d203d fix(deps): update ktor to v2.2.4 (#430)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 10:38:18 +00:00
bd05dbcfcb chore(deps): update plugin io.github.gradle-nexus.publish-plugin to v1.3.0 (#431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 08:48:23 +00:00
cb5c0e71a3 fix(deps): update dependency com.google.protobuf:protobuf-java to v3.22.2 (#429)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 08:45:44 +00:00
a209cafa74 chore(deps): update dependency gradle to v7.6.1 (#428)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-16 07:27:45 +00:00
3d27d30a31 feat: support no request body for post, put and patch (#427) 2023-03-15 12:39:35 +00:00
42 changed files with 831 additions and 66 deletions

View File

@ -12,6 +12,36 @@
## Released ## Released
## [3.14.3] - May 22nd, 2023
### Added
- Added `required` parameter in request info builder.
## [3.14.2] - May 8rd, 2023
### Changed
- Fixed bug where routes were not resolving when a parameter was declared via the ktor SDK
## [3.14.1] - April 28th, 2023
### Changed
- Generating enrichments for generic classes no longer throws the `Slugs should not be generated for field enrichments` error.
## [3.14.0] - April 6th, 2023
### Added
- Add support for response headers
## [3.13.0] - March 15th, 2023
### Changed
- Post, Put, and Patch now support not providing request info
## [3.12.0] - March 14th, 2023 ## [3.12.0] - March 14th, 2023
### Added ### Added

View File

@ -3,3 +3,7 @@
[![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium) [![version](https://img.shields.io/maven-central/v/io.bkbn/kompendium-core?style=flat-square)](https://search.maven.org/search?q=io.bkbn%20kompendium)
Documentation is stored in the `docs` folder and is hosted [here](https://bkbn.gitbook.io/kompendium) Documentation is stored in the `docs` folder and is hosted [here](https://bkbn.gitbook.io/kompendium)
## Showcase
If you would like to showcase docs that you build using Kompendium, add them to [the showcase discussion](https://github.com/bkbnio/kompendium/discussions/444)

View File

@ -1,12 +1,12 @@
plugins { plugins {
kotlin("jvm") version "1.8.10" apply false kotlin("jvm") version "1.8.21" apply false
kotlin("plugin.serialization") version "1.8.10" apply false kotlin("plugin.serialization") version "1.8.21" apply false
id("io.bkbn.sourdough.library.jvm") version "0.12.0" apply false id("io.bkbn.sourdough.library.jvm") version "0.12.0" apply false
id("io.bkbn.sourdough.application.jvm") version "0.12.0" apply false id("io.bkbn.sourdough.application.jvm") version "0.12.0" apply false
id("io.bkbn.sourdough.root") version "0.12.0" id("io.bkbn.sourdough.root") version "0.12.0"
id("com.github.jakemarsden.git-hooks") version "0.0.2" id("com.github.jakemarsden.git-hooks") version "0.0.2"
id("org.jetbrains.kotlinx.kover") version "0.6.1" id("org.jetbrains.kotlinx.kover") version "0.6.1"
id("io.github.gradle-nexus.publish-plugin") version "1.2.0" id("io.github.gradle-nexus.publish-plugin") version "1.3.0"
} }
gitHooks { gitHooks {

View File

@ -57,9 +57,9 @@ dependencies {
testFixturesApi("io.ktor:ktor-client:$ktorVersion") testFixturesApi("io.ktor:ktor-client:$ktorVersion")
testFixturesApi("io.ktor:ktor-client-cio:$ktorVersion") testFixturesApi("io.ktor:ktor-client-cio:$ktorVersion")
testFixturesApi("dev.forst:ktor-api-key:2.2.2") testFixturesApi("dev.forst:ktor-api-key:2.2.4")
testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") testFixturesApi("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
} }
testing { testing {

View File

@ -1,7 +1,7 @@
package io.bkbn.kompendium.core.metadata package io.bkbn.kompendium.core.metadata
sealed interface MethodInfoWithRequest : MethodInfo { sealed interface MethodInfoWithRequest : MethodInfo {
val request: RequestInfo val request: RequestInfo?
abstract class Builder<T : MethodInfoWithRequest> : MethodInfo.Builder<T>() { abstract class Builder<T : MethodInfoWithRequest> : MethodInfo.Builder<T>() {
internal var request: RequestInfo? = null internal var request: RequestInfo? = null

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PatchInfo private constructor( class PatchInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -26,7 +26,7 @@ class PatchInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PatchInfo>() { class Builder : MethodInfoWithRequest.Builder<PatchInfo>() {
override fun build() = PatchInfo( override fun build() = PatchInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PostInfo private constructor( class PostInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -26,7 +26,7 @@ class PostInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PostInfo>() { class Builder : MethodInfoWithRequest.Builder<PostInfo>() {
override fun build() = PostInfo( override fun build() = PostInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,

View File

@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
class PutInfo private constructor( class PutInfo private constructor(
override val request: RequestInfo, override val request: RequestInfo?,
override val errors: MutableList<ResponseInfo>, override val errors: MutableList<ResponseInfo>,
override val response: ResponseInfo, override val response: ResponseInfo,
override val tags: Set<String>, override val tags: Set<String>,
@ -26,7 +26,7 @@ class PutInfo private constructor(
class Builder : MethodInfoWithRequest.Builder<PutInfo>() { class Builder : MethodInfoWithRequest.Builder<PutInfo>() {
override fun build() = PutInfo( override fun build() = PutInfo(
request = request ?: error("request info must be present"), request = request,
errors = errors, errors = errors,
response = response ?: error("response info must be present"), response = response ?: error("response info must be present"),
tags = tags, tags = tags,

View File

@ -10,7 +10,8 @@ class RequestInfo private constructor(
val typeEnrichment: TypeEnrichment<*>?, val typeEnrichment: TypeEnrichment<*>?,
val description: String, val description: String,
val examples: Map<String, MediaType.Example>?, val examples: Map<String, MediaType.Example>?,
val mediaTypes: Set<String> val mediaTypes: Set<String>,
val required: Boolean
) { ) {
companion object { companion object {
@ -27,6 +28,11 @@ class RequestInfo private constructor(
private var description: String? = null private var description: String? = null
private var examples: Map<String, MediaType.Example>? = null private var examples: Map<String, MediaType.Example>? = null
private var mediaTypes: Set<String>? = null private var mediaTypes: Set<String>? = null
private var required: Boolean? = null
fun required(r: Boolean) = apply {
this.required = r
}
fun requestType(t: KType) = apply { fun requestType(t: KType) = apply {
this.requestType = t this.requestType = t
@ -56,7 +62,8 @@ class RequestInfo private constructor(
description = description ?: error("Description must be present"), description = description ?: error("Description must be present"),
typeEnrichment = typeEnrichment, typeEnrichment = typeEnrichment,
examples = examples, examples = examples,
mediaTypes = mediaTypes ?: setOf("application/json") mediaTypes = mediaTypes ?: setOf("application/json"),
required = required ?: true
) )
} }
} }

View File

@ -1,6 +1,7 @@
package io.bkbn.kompendium.core.metadata package io.bkbn.kompendium.core.metadata
import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.enrichment.TypeEnrichment
import io.bkbn.kompendium.oas.payload.Header
import io.bkbn.kompendium.oas.payload.MediaType import io.bkbn.kompendium.oas.payload.MediaType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import kotlin.reflect.KType import kotlin.reflect.KType
@ -12,7 +13,8 @@ class ResponseInfo private constructor(
val typeEnrichment: TypeEnrichment<*>?, val typeEnrichment: TypeEnrichment<*>?,
val description: String, val description: String,
val examples: Map<String, MediaType.Example>?, val examples: Map<String, MediaType.Example>?,
val mediaTypes: Set<String> val mediaTypes: Set<String>,
val responseHeaders: Map<String, Header>?
) { ) {
companion object { companion object {
@ -30,6 +32,11 @@ class ResponseInfo private constructor(
private var description: String? = null private var description: String? = null
private var examples: Map<String, MediaType.Example>? = null private var examples: Map<String, MediaType.Example>? = null
private var mediaTypes: Set<String>? = null private var mediaTypes: Set<String>? = null
private var responseHeaders: Map<String, Header>? = null
fun responseHeaders(headers: Map<String, Header>) = apply {
this.responseHeaders = headers
}
fun responseCode(code: HttpStatusCode) = apply { fun responseCode(code: HttpStatusCode) = apply {
this.responseCode = code this.responseCode = code
@ -64,7 +71,8 @@ class ResponseInfo private constructor(
description = description ?: error("You must provide a description in order to build a Response!"), description = description ?: error("You must provide a description in order to build a Response!"),
typeEnrichment = typeEnrichment, typeEnrichment = typeEnrichment,
examples = examples, examples = examples,
mediaTypes = mediaTypes ?: setOf("application/json") mediaTypes = mediaTypes ?: setOf("application/json"),
responseHeaders = responseHeaders
) )
} }
} }

View File

@ -86,6 +86,7 @@ object NotarizedRoute {
?: it ?: it
} }
.replace(Regex("/\\(.+\\)"), "") .replace(Regex("/\\(.+\\)"), "")
.replace(Regex("/\\[.+\\]"), "")
fun Route.collectAuthMethods() = toString() fun Route.collectAuthMethods() = toString()
.split("/") .split("/")

View File

@ -72,13 +72,15 @@ object Helpers {
when (this) { when (this) {
is MethodInfoWithRequest -> { is MethodInfoWithRequest -> {
this.request?.let { reqInfo ->
SchemaGenerator.fromTypeOrUnit( SchemaGenerator.fromTypeOrUnit(
type = this.request.requestType, type = reqInfo.requestType,
cache = spec.components.schemas, cache = spec.components.schemas,
schemaConfigurator = schemaConfigurator, schemaConfigurator = schemaConfigurator,
enrichment = this.request.typeEnrichment, enrichment = reqInfo.typeEnrichment,
)?.let { schema -> )?.let { schema ->
spec.components.schemas[this.request.requestType.getSlug(this.request.typeEnrichment)] = schema spec.components.schemas[reqInfo.requestType.getSlug(reqInfo.typeEnrichment)] = schema
}
} }
} }
@ -121,21 +123,24 @@ object Helpers {
?.map { listOf(it).toMap() } ?.map { listOf(it).toMap() }
?.toMutableList(), ?.toMutableList(),
requestBody = when (this) { requestBody = when (this) {
is MethodInfoWithRequest -> Request( is MethodInfoWithRequest -> this.request?.let { reqInfo ->
description = this.request.description, Request(
content = this.request.requestType.toReferenceContent( description = reqInfo.description,
examples = this.request.examples, content = reqInfo.requestType.toReferenceContent(
mediaTypes = this.request.mediaTypes, examples = reqInfo.examples,
enrichment = this.request.typeEnrichment mediaTypes = reqInfo.mediaTypes,
enrichment = reqInfo.typeEnrichment
), ),
required = true required = reqInfo.required
) )
}
else -> null else -> null
}, },
responses = mapOf( responses = mapOf(
this.response.responseCode.value to Response( this.response.responseCode.value to Response(
description = this.response.description, description = this.response.description,
headers = this.response.responseHeaders,
content = this.response.responseType.toReferenceContent( content = this.response.responseType.toReferenceContent(
examples = this.response.examples, examples = this.response.examples,
mediaTypes = this.response.mediaTypes, mediaTypes = this.response.mediaTypes,
@ -148,6 +153,7 @@ object Helpers {
private fun List<ResponseInfo>.toResponseMap(): Map<Int, Response> = associate { error -> private fun List<ResponseInfo>.toResponseMap(): Map<Int, Response> = associate { error ->
error.responseCode.value to Response( error.responseCode.value to Response(
description = error.description, description = error.description,
headers = error.responseHeaders,
content = error.responseType.toReferenceContent( content = error.responseType.toReferenceContent(
examples = error.examples, examples = error.examples,
mediaTypes = error.mediaTypes, mediaTypes = error.mediaTypes,

View File

@ -11,6 +11,7 @@ import io.bkbn.kompendium.core.util.defaultAuthConfig
import io.bkbn.kompendium.core.util.defaultField import io.bkbn.kompendium.core.util.defaultField
import io.bkbn.kompendium.core.util.defaultParameter import io.bkbn.kompendium.core.util.defaultParameter
import io.bkbn.kompendium.core.util.doubleConstraints import io.bkbn.kompendium.core.util.doubleConstraints
import io.bkbn.kompendium.core.util.enrichedGenericResponse
import io.bkbn.kompendium.core.util.enrichedComplexGenericType import io.bkbn.kompendium.core.util.enrichedComplexGenericType
import io.bkbn.kompendium.core.util.enrichedNestedCollection import io.bkbn.kompendium.core.util.enrichedNestedCollection
import io.bkbn.kompendium.core.util.enrichedSimpleRequest import io.bkbn.kompendium.core.util.enrichedSimpleRequest
@ -48,9 +49,12 @@ import io.bkbn.kompendium.core.util.polymorphicCollectionResponse
import io.bkbn.kompendium.core.util.polymorphicException import io.bkbn.kompendium.core.util.polymorphicException
import io.bkbn.kompendium.core.util.polymorphicMapResponse import io.bkbn.kompendium.core.util.polymorphicMapResponse
import io.bkbn.kompendium.core.util.polymorphicResponse import io.bkbn.kompendium.core.util.polymorphicResponse
import io.bkbn.kompendium.core.util.postNoReqBody
import io.bkbn.kompendium.core.util.primitives import io.bkbn.kompendium.core.util.primitives
import io.bkbn.kompendium.core.util.reqRespExamples import io.bkbn.kompendium.core.util.reqRespExamples
import io.bkbn.kompendium.core.util.optionalReqExample
import io.bkbn.kompendium.core.util.requiredParams import io.bkbn.kompendium.core.util.requiredParams
import io.bkbn.kompendium.core.util.responseHeaders
import io.bkbn.kompendium.core.util.returnsList import io.bkbn.kompendium.core.util.returnsList
import io.bkbn.kompendium.core.util.rootRoute import io.bkbn.kompendium.core.util.rootRoute
import io.bkbn.kompendium.core.util.samePathDifferentMethodsAndAuth import io.bkbn.kompendium.core.util.samePathDifferentMethodsAndAuth
@ -64,6 +68,7 @@ import io.bkbn.kompendium.core.util.stringContentEncodingConstraints
import io.bkbn.kompendium.core.util.stringPatternConstraints import io.bkbn.kompendium.core.util.stringPatternConstraints
import io.bkbn.kompendium.core.util.topLevelNullable import io.bkbn.kompendium.core.util.topLevelNullable
import io.bkbn.kompendium.core.util.trailingSlash import io.bkbn.kompendium.core.util.trailingSlash
import io.bkbn.kompendium.core.util.paramWrapper
import io.bkbn.kompendium.core.util.unbackedFieldsResponse import io.bkbn.kompendium.core.util.unbackedFieldsResponse
import io.bkbn.kompendium.core.util.withOperationId import io.bkbn.kompendium.core.util.withOperationId
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
@ -129,6 +134,12 @@ class KompendiumTest : DescribeSpec({
it("Can override media types") { it("Can override media types") {
openApiTestAllSerializers("T0052__override_media_types.json") { overrideMediaTypes() } openApiTestAllSerializers("T0052__override_media_types.json") { overrideMediaTypes() }
} }
it("Can support a post request with no request body") {
openApiTestAllSerializers("T0065__post_no_req_body.json") { postNoReqBody() }
}
it("Can notarize a route with response headers") {
openApiTestAllSerializers("T0066__notarized_get_with_response_headers.json") { responseHeaders() }
}
} }
describe("Route Parsing") { describe("Route Parsing") {
it("Can parse a simple path and store it under the expected route") { it("Can parse a simple path and store it under the expected route") {
@ -143,6 +154,9 @@ class KompendiumTest : DescribeSpec({
it("Can notarize a route with a trailing slash") { it("Can notarize a route with a trailing slash") {
openApiTestAllSerializers("T0015__trailing_slash.json") { trailingSlash() } openApiTestAllSerializers("T0015__trailing_slash.json") { trailingSlash() }
} }
it("Can notarize a route with a parameter") {
openApiTestAllSerializers("T0068__param_wrapper.json") { paramWrapper() }
}
} }
describe("Exceptions") { describe("Exceptions") {
it("Can add an exception status code to a response") { it("Can add an exception status code to a response") {
@ -165,6 +179,9 @@ class KompendiumTest : DescribeSpec({
it("Can describe example parameters") { it("Can describe example parameters") {
openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() } openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() }
} }
it("Can generate example optional request body") {
openApiTestAllSerializers("T0069__example_optional_req.json") { optionalReqExample() }
}
} }
describe("Defaults") { describe("Defaults") {
it("Can generate a default parameter value") { it("Can generate a default parameter value") {
@ -444,6 +461,9 @@ class KompendiumTest : DescribeSpec({
it("Can enrich a complex generic type") { it("Can enrich a complex generic type") {
openApiTestAllSerializers("T0057__enriched_complex_generic_type.json") { enrichedComplexGenericType() } openApiTestAllSerializers("T0057__enriched_complex_generic_type.json") { enrichedComplexGenericType() }
} }
it("Can enrich a generic object") {
openApiTestAllSerializers("T0067__enriched_generic_object.json") { enrichedGenericResponse() }
}
} }
describe("Constraints") { describe("Constraints") {
it("Can apply constraints to an int field") { it("Can apply constraints to an int field") {

View File

@ -6,6 +6,7 @@ import io.bkbn.kompendium.core.fixtures.NestedComplexItem
import io.bkbn.kompendium.core.fixtures.TestCreatedResponse import io.bkbn.kompendium.core.fixtures.TestCreatedResponse
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.core.fixtures.TestSimpleRequest import io.bkbn.kompendium.core.fixtures.TestSimpleRequest
import io.bkbn.kompendium.core.fixtures.GenericObject
import io.bkbn.kompendium.core.metadata.GetInfo import io.bkbn.kompendium.core.metadata.GetInfo
import io.bkbn.kompendium.core.metadata.PostInfo import io.bkbn.kompendium.core.metadata.PostInfo
import io.bkbn.kompendium.core.plugin.NotarizedRoute import io.bkbn.kompendium.core.plugin.NotarizedRoute
@ -135,3 +136,33 @@ fun Routing.enrichedComplexGenericType() {
} }
} }
} }
fun Routing.enrichedGenericResponse() {
route("/example") {
install(NotarizedRoute()) {
get = GetInfo.builder {
summary(TestModules.defaultPathSummary)
description(TestModules.defaultPathDescription)
response {
responseType(
enrichment = TypeEnrichment("generic") {
GenericObject<TestSimpleRequest>::data {
description = "A simple description"
typeEnrichment = TypeEnrichment("simple") {
TestSimpleRequest::a {
description = "A simple description"
}
TestSimpleRequest::b {
deprecated = true
}
}
}
}
)
description("A good response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}

View File

@ -55,3 +55,30 @@ fun Routing.exampleParams() = basicGetGenerator<TestResponse>(
) )
) )
) )
fun Routing.optionalReqExample() {
route(rootPath) {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
request {
description(defaultRequestDescription)
requestType<TestRequest>()
examples(
"Testerina" to TestRequest(TestNested("asdf"), 1.5, emptyList())
)
required(false)
}
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
examples(
"Testerino" to TestResponse("Heya")
)
}
}
}
}
}

View File

@ -20,7 +20,9 @@ import io.bkbn.kompendium.core.util.TestModules.defaultPathSummary
import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription import io.bkbn.kompendium.core.util.TestModules.defaultResponseDescription
import io.bkbn.kompendium.core.util.TestModules.rootPath import io.bkbn.kompendium.core.util.TestModules.rootPath
import io.bkbn.kompendium.json.schema.definition.TypeDefinition import io.bkbn.kompendium.json.schema.definition.TypeDefinition
import io.bkbn.kompendium.oas.payload.Header
import io.bkbn.kompendium.oas.payload.Parameter import io.bkbn.kompendium.oas.payload.Parameter
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.call import io.ktor.server.application.call
import io.ktor.server.application.install import io.ktor.server.application.install
@ -56,6 +58,38 @@ fun Routing.notarizedGet() {
} }
} }
fun Routing.responseHeaders() {
route(defaultPath) {
install(NotarizedRoute()) {
parameters = defaultParams
get = GetInfo.builder {
response {
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
description(defaultResponseDescription)
responseHeaders(
mapOf(
HttpHeaders.ETag to Header(
TypeDefinition.STRING,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag"
),
HttpHeaders.LastModified to Header(
TypeDefinition.STRING,
"https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified"
),
)
)
}
summary(defaultPathSummary)
description(defaultPathDescription)
}
}
get {
call.respondText { "hey dude ‼️ congrats on the get request" }
}
}
}
fun Routing.notarizedPost() { fun Routing.notarizedPost() {
route(defaultPath) { route(defaultPath) {
install(NotarizedRoute()) { install(NotarizedRoute()) {
@ -299,3 +333,19 @@ fun Routing.overrideMediaTypes() {
} }
} }
} }
fun Routing.postNoReqBody() {
route("/no_req_body") {
install(NotarizedRoute()) {
post = PostInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
responseType<TestResponse>()
description("Cool response")
responseCode(HttpStatusCode.Created)
}
}
}
}
}

View File

@ -14,6 +14,7 @@ import io.ktor.http.HttpStatusCode
import io.ktor.server.application.install import io.ktor.server.application.install
import io.ktor.server.routing.Routing import io.ktor.server.routing.Routing
import io.ktor.server.routing.route import io.ktor.server.routing.route
import io.ktor.server.routing.param
fun Routing.simplePathParsing() { fun Routing.simplePathParsing() {
route("/this") { route("/this") {
@ -100,3 +101,32 @@ fun Routing.trailingSlash() {
} }
} }
} }
fun Routing.paramWrapper() {
route("/test") {
param("a") {
param("b") {
param("c") {
install(NotarizedRoute()) {
parameters = listOf(
Parameter(
name = "test",
`in` = Parameter.Location.query,
schema = TypeDefinition.STRING
)
)
get = GetInfo.builder {
summary(defaultPathSummary)
description(defaultPathDescription)
response {
description(defaultResponseDescription)
responseCode(HttpStatusCode.OK)
responseType<TestResponse>()
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,72 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/no_req_body": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"201": {
"description": "Cool response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,110 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/test/{a}": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"headers": {
"ETag": {
"schema": {
"type": "string"
},
"description": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag",
"required": true,
"deprecated": false
},
"Last-Modified": {
"schema": {
"type": "string"
},
"description": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified",
"required": true,
"deprecated": false
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "a",
"in": "path",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
},
{
"name": "aa",
"in": "query",
"schema": {
"type": "number",
"format": "int32"
},
"required": true,
"deprecated": false
}
]
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,91 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/example": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"201": {
"description": "A good response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GenericObject-TestSimpleRequest-generic"
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"GenericObject-TestSimpleRequest-generic": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/TestSimpleRequest-simple",
"description": "A simple description"
}
},
"required": [
"data"
]
},
"TestSimpleRequest-simple": {
"type": "object",
"properties": {
"a": {
"type": "string",
"description": "A simple description"
},
"b": {
"type": "number",
"format": "int32",
"deprecated": true
}
},
"required": [
"a",
"b"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,82 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/test": {
"get": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
}
}
}
}
},
"deprecated": false
},
"parameters": [
{
"name": "test",
"in": "query",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
}
]
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,136 @@
{
"openapi": "3.1.0",
"jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
"info": {
"title": "Test API",
"version": "1.33.7",
"description": "An amazing, fully-ish 😉 generated API spec",
"termsOfService": "https://example.com",
"contact": {
"name": "Homer Simpson",
"url": "https://gph.is/1NPUDiM",
"email": "chunkylover53@aol.com"
},
"license": {
"name": "MIT",
"url": "https://github.com/bkbnio/kompendium/blob/main/LICENSE"
}
},
"servers": [
{
"url": "https://myawesomeapi.com",
"description": "Production instance of my API"
},
{
"url": "https://staging.myawesomeapi.com",
"description": "Where the fun stuff happens"
}
],
"paths": {
"/": {
"post": {
"tags": [],
"summary": "Great Summary!",
"description": "testing more",
"parameters": [],
"requestBody": {
"description": "You gotta send it",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestRequest"
},
"examples": {
"Testerina": {
"value": {
"fieldName": {
"nesty": "asdf"
},
"b": 1.5,
"aaa": []
}
}
}
}
},
"required": false
},
"responses": {
"200": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/TestResponse"
},
"examples": {
"Testerino": {
"value": {
"c": "Heya"
}
}
}
}
}
}
},
"deprecated": false
},
"parameters": []
}
},
"webhooks": {},
"components": {
"schemas": {
"TestResponse": {
"type": "object",
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
]
},
"TestRequest": {
"type": "object",
"properties": {
"aaa": {
"items": {
"type": "number",
"format": "int64"
},
"type": "array"
},
"b": {
"type": "number",
"format": "double"
},
"fieldName": {
"$ref": "#/components/schemas/TestNested"
}
},
"required": [
"aaa",
"b",
"fieldName"
]
},
"TestNested": {
"type": "object",
"properties": {
"nesty": {
"type": "string"
}
},
"required": [
"nesty"
]
}
},
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -180,6 +180,10 @@ data class SerialNameObject(
val camelCaseName: String val camelCaseName: String
) )
data class GenericObject<T>(
val data: T
)
enum class Color { enum class Color {
RED, RED,
GREEN, GREEN,

View File

@ -22,6 +22,8 @@ formatting:
indentSize: 2 indentSize: 2
ImportOrdering: ImportOrdering:
active: false active: false
EnumEntryNameCase:
active: false
naming: naming:
ConstructorParameterNaming: ConstructorParameterNaming:
active: false active: false

View File

@ -1,13 +1,13 @@
# Summary # Summary
* [Introduction](index.md) * [Introduction](index.md)
* [Helpers](helpers/index.md)
* [Protobuf java converter](helpers/protobuf_java_converter.md)
* [Concepts](concepts/index.md)
* [Enrichment](concepts/enrichment.md)
* [Plugins](plugins/index.md) * [Plugins](plugins/index.md)
* [Notarized Application](plugins/notarized_application.md) * [Notarized Application](plugins/notarized_application.md)
* [Notarized Route](plugins/notarized_route.md) * [Notarized Route](plugins/notarized_route.md)
* [Notarized Locations](plugins/notarized_locations.md) * [Notarized Locations](plugins/notarized_locations.md)
* [Notarized Resources](plugins/notarized_resources.md) * [Notarized Resources](plugins/notarized_resources.md)
* [Concepts](concepts/index.md)
* [Enrichment](concepts/enrichment.md)
* [Helpers](helpers/index.md)
* [Protobuf java converter](helpers/protobuf_java_converter.md)
* [The Playground](playground.md) * [The Playground](playground.md)

View File

@ -1,5 +1,5 @@
# Kompendium # Kompendium
project.version=3.12.0 project.version=3.14.3
# Kotlin # Kotlin
kotlin.code.style=official kotlin.code.style=official
# Gradle # Gradle
@ -9,6 +9,6 @@ org.gradle.jvmargs=-Xmx2000m
org.gradle.parallel=true org.gradle.parallel=true
# Dependencies # Dependencies
ktorVersion=2.2.3 ktorVersion=2.3.0
kotestVersion=5.5.5 kotestVersion=5.6.2
detektVersion=1.21.0 detektVersion=1.22.0

Binary file not shown.

View File

@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

19
gradlew vendored
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +80,10 @@ do
esac esac
done done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # This is normally unused
# shellcheck disable=SC2034
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@ -143,12 +140,16 @@ fi
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | soft) :;; #(
*) *)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@ -193,6 +194,10 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command; # Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in # shell script including quotes and variable substitutions, so put them in

1
gradlew.bat vendored
View File

@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%

View File

@ -23,8 +23,8 @@ dependencies {
// Kompendium // Kompendium
api(projects.kompendiumEnrichment) api(projects.kompendiumEnrichment)
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10") implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.21")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
// Formatting // Formatting
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")

View File

@ -34,7 +34,6 @@ object SimpleObjectHandler {
schemaConfigurator: SchemaConfigurator, schemaConfigurator: SchemaConfigurator,
enrichment: TypeEnrichment<*>?, enrichment: TypeEnrichment<*>?,
): JsonSchema { ): JsonSchema {
cache[type.getSlug(enrichment)] = ReferenceDefinition(type.getReferenceSlug(enrichment)) cache[type.getSlug(enrichment)] = ReferenceDefinition(type.getReferenceSlug(enrichment))
val typeMap = clazz.typeParameters.zip(type.arguments).toMap() val typeMap = clazz.typeParameters.zip(type.arguments).toMap()
@ -134,8 +133,8 @@ object SimpleObjectHandler {
?: error("This indicates a bug in Kompendium, please open a GitHub issue") ?: error("This indicates a bug in Kompendium, please open a GitHub issue")
return SchemaGenerator.fromTypeToSchema(type, cache, schemaConfigurator, propEnrichment?.typeEnrichment).let { return SchemaGenerator.fromTypeToSchema(type, cache, schemaConfigurator, propEnrichment?.typeEnrichment).let {
if (it.isOrContainsObjectOrEnumDef()) { if (it.isOrContainsObjectOrEnumDef()) {
cache[type.getSlug(propEnrichment)] = it cache[type.getSlug(propEnrichment?.typeEnrichment)] = it
ReferenceDefinition(type.getReferenceSlug(propEnrichment)) ReferenceDefinition(type.getReferenceSlug(propEnrichment?.typeEnrichment))
} else { } else {
it it
} }
@ -176,6 +175,7 @@ object SimpleObjectHandler {
maxItems = maxItems, maxItems = maxItems,
uniqueItems = uniqueItems, uniqueItems = uniqueItems,
) )
is EnumDefinition -> schema.copy(deprecated = deprecated, description = description) is EnumDefinition -> schema.copy(deprecated = deprecated, description = description)
is MapDefinition -> schema.copy(deprecated = deprecated, description = description) is MapDefinition -> schema.copy(deprecated = deprecated, description = description)
is NullableDefinition -> schema.copy(deprecated = deprecated, description = description) is NullableDefinition -> schema.copy(deprecated = deprecated, description = description)

View File

@ -7,11 +7,12 @@ import io.bkbn.kompendium.core.fixtures.ObjectWithEnum
import io.bkbn.kompendium.core.fixtures.SerialNameObject import io.bkbn.kompendium.core.fixtures.SerialNameObject
import io.bkbn.kompendium.core.fixtures.SimpleEnum import io.bkbn.kompendium.core.fixtures.SimpleEnum
import io.bkbn.kompendium.core.fixtures.SlammaJamma import io.bkbn.kompendium.core.fixtures.SlammaJamma
import io.bkbn.kompendium.core.fixtures.TestHelpers.getFileSnapshot
import io.bkbn.kompendium.core.fixtures.TestResponse import io.bkbn.kompendium.core.fixtures.TestResponse
import io.bkbn.kompendium.core.fixtures.TestSimpleRequest import io.bkbn.kompendium.core.fixtures.TestSimpleRequest
import io.bkbn.kompendium.core.fixtures.TransientObject import io.bkbn.kompendium.core.fixtures.TransientObject
import io.bkbn.kompendium.core.fixtures.UnbackedObject import io.bkbn.kompendium.core.fixtures.UnbackedObject
import io.bkbn.kompendium.core.fixtures.GenericObject
import io.bkbn.kompendium.core.fixtures.TestHelpers.getFileSnapshot
import io.bkbn.kompendium.enrichment.TypeEnrichment import io.bkbn.kompendium.enrichment.TypeEnrichment
import io.bkbn.kompendium.json.schema.definition.JsonSchema import io.bkbn.kompendium.json.schema.definition.JsonSchema
import io.kotest.assertions.json.shouldEqualJson import io.kotest.assertions.json.shouldEqualJson
@ -62,6 +63,9 @@ class SchemaGeneratorTest : DescribeSpec({
it("Can generate the schema for object with SerialName annotation") { it("Can generate the schema for object with SerialName annotation") {
jsonSchemaTest<SerialNameObject>("T0020__serial_name_object.json") jsonSchemaTest<SerialNameObject>("T0020__serial_name_object.json")
} }
it("Can generate the schema for object with generic property") {
jsonSchemaTest<GenericObject<TestSimpleRequest>>("T0024__generic_object.json")
}
} }
describe("Enums") { describe("Enums") {
it("Can generate the schema for a simple enum") { it("Can generate the schema for a simple enum") {
@ -135,6 +139,24 @@ class SchemaGeneratorTest : DescribeSpec({
} }
) )
} }
it("Can properly assign a reference to a generic object") {
jsonSchemaTest<GenericObject<TestSimpleRequest>>(
snapshotName = "T0025__enrichment_generic_object.json",
enrichment = TypeEnrichment("generic") {
GenericObject<TestSimpleRequest>::data {
description = "This is a generic param"
typeEnrichment = TypeEnrichment("simple") {
TestSimpleRequest::a {
description = "This is a simple description"
}
TestSimpleRequest::b {
deprecated = true
}
}
}
}
)
}
} }
}) { }) {
companion object { companion object {

View File

@ -0,0 +1,11 @@
{
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/TestSimpleRequest"
}
},
"required": [
"data"
]
}

View File

@ -0,0 +1,12 @@
{
"type": "object",
"properties": {
"data": {
"description": "This is a generic param",
"$ref": "#/components/schemas/TestSimpleRequest-simple"
}
},
"required": [
"data"
]
}

View File

@ -22,8 +22,8 @@ dependencies {
// IMPLEMENTATION // IMPLEMENTATION
implementation(projects.kompendiumCore) implementation(projects.kompendiumCore)
implementation("io.ktor:ktor-server-core:2.2.3") implementation("io.ktor:ktor-server-core:2.3.0")
implementation("io.ktor:ktor-server-locations:2.2.3") implementation("io.ktor:ktor-server-locations:2.3.0")
// TESTING // TESTING

View File

@ -7,6 +7,7 @@ data class Listing(val name: String, val page: Int)
data class Type(val name: String) { data class Type(val name: String) {
@Location("/edit") @Location("/edit")
data class Edit(val parent: Type) data class Edit(val parent: Type)
@Location("/other/{page}") @Location("/other/{page}")
data class Other(val parent: Type, val page: Int) data class Other(val parent: Type, val page: Int)
} }

View File

@ -22,7 +22,7 @@ dependencies {
api(projects.kompendiumJsonSchema) api(projects.kompendiumJsonSchema)
api(projects.kompendiumEnrichment) api(projects.kompendiumEnrichment)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
// Formatting // Formatting
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")

View File

@ -37,12 +37,12 @@ dependencies {
implementation("org.apache.logging.log4j:log4j-api-kotlin:1.2.0") implementation("org.apache.logging.log4j:log4j-api-kotlin:1.2.0")
implementation("org.apache.logging.log4j:log4j-api:2.20.0") implementation("org.apache.logging.log4j:log4j-api:2.20.0")
implementation("org.apache.logging.log4j:log4j-core:2.20.0") implementation("org.apache.logging.log4j:log4j-core:2.20.0")
implementation("org.slf4j:slf4j-api:2.0.6") implementation("org.slf4j:slf4j-api:2.0.7")
implementation("org.slf4j:slf4j-simple:2.0.6") implementation("org.slf4j:slf4j-simple:2.0.7")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0")
implementation("joda-time:joda-time:2.12.2") implementation("joda-time:joda-time:2.12.5")
} }

View File

@ -22,9 +22,9 @@ dependencies {
implementation(projects.kompendiumJsonSchema) implementation(projects.kompendiumJsonSchema)
implementation("com.google.protobuf:protobuf-java:3.22.0") implementation("com.google.protobuf:protobuf-java:3.23.1")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.10") implementation("org.jetbrains.kotlin:kotlin-reflect:1.8.21")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
// Formatting // Formatting
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion") detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")

View File

@ -22,8 +22,8 @@ dependencies {
// IMPLEMENTATION // IMPLEMENTATION
implementation(projects.kompendiumCore) implementation(projects.kompendiumCore)
implementation("io.ktor:ktor-server-core:2.2.3") implementation("io.ktor:ktor-server-core:2.3.0")
implementation("io.ktor:ktor-server-resources:2.2.3") implementation("io.ktor:ktor-server-resources:2.3.0")
// TESTING // TESTING

View File

@ -11,6 +11,7 @@ data class Type(val name: String) {
@Serializable @Serializable
@Resource("/edit") @Resource("/edit")
data class Edit(val parent: Type) data class Edit(val parent: Type)
@Serializable @Serializable
@Resource("/other/{page}") @Resource("/other/{page}")
data class Other(val parent: Type, val page: Int) data class Other(val parent: Type, val page: Int)