From 3d27d30a316499ccd6858140ce1d13cd93ffb728 Mon Sep 17 00:00:00 2001 From: Ryan Brink <5607577+unredundant@users.noreply.github.com> Date: Wed, 15 Mar 2023 08:39:35 -0400 Subject: [PATCH] feat: support no request body for post, put and patch (#427) --- CHANGELOG.md | 6 ++ .../core/metadata/MethodInfoWithRequest.kt | 2 +- .../kompendium/core/metadata/PatchInfo.kt | 4 +- .../bkbn/kompendium/core/metadata/PostInfo.kt | 4 +- .../bkbn/kompendium/core/metadata/PutInfo.kt | 4 +- .../io/bkbn/kompendium/core/util/Helpers.kt | 36 +++++----- .../io/bkbn/kompendium/core/KompendiumTest.kt | 4 ++ .../kompendium/core/util/NotarizedOpenApi.kt | 16 +++++ .../resources/T0065__post_no_req_body.json | 72 +++++++++++++++++++ gradle.properties | 2 +- 10 files changed, 126 insertions(+), 24 deletions(-) create mode 100644 core/src/test/resources/T0065__post_no_req_body.json diff --git a/CHANGELOG.md b/CHANGELOG.md index ee1671fee..fd05fa3f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ ## Released +## [3.13.0] - March 15th, 2023 + +### Changed + +- Post, Put, and Patch now support not providing request info + ## [3.12.0] - March 14th, 2023 ### Added diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/MethodInfoWithRequest.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/MethodInfoWithRequest.kt index af4c177ef..3bbb259d3 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/MethodInfoWithRequest.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/MethodInfoWithRequest.kt @@ -1,7 +1,7 @@ package io.bkbn.kompendium.core.metadata sealed interface MethodInfoWithRequest : MethodInfo { - val request: RequestInfo + val request: RequestInfo? abstract class Builder : MethodInfo.Builder() { internal var request: RequestInfo? = null diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PatchInfo.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PatchInfo.kt index eabf4f7fb..9cefdb424 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PatchInfo.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PatchInfo.kt @@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation import io.bkbn.kompendium.oas.payload.Parameter class PatchInfo private constructor( - override val request: RequestInfo, + override val request: RequestInfo?, override val errors: MutableList, override val response: ResponseInfo, override val tags: Set, @@ -26,7 +26,7 @@ class PatchInfo private constructor( class Builder : MethodInfoWithRequest.Builder() { override fun build() = PatchInfo( - request = request ?: error("request info must be present"), + request = request, errors = errors, response = response ?: error("response info must be present"), tags = tags, diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PostInfo.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PostInfo.kt index d7a406fdc..2020fd176 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PostInfo.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PostInfo.kt @@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation import io.bkbn.kompendium.oas.payload.Parameter class PostInfo private constructor( - override val request: RequestInfo, + override val request: RequestInfo?, override val errors: MutableList, override val response: ResponseInfo, override val tags: Set, @@ -26,7 +26,7 @@ class PostInfo private constructor( class Builder : MethodInfoWithRequest.Builder() { override fun build() = PostInfo( - request = request ?: error("request info must be present"), + request = request, errors = errors, response = response ?: error("response info must be present"), tags = tags, diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PutInfo.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PutInfo.kt index 152c30b64..f4c508b71 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PutInfo.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/PutInfo.kt @@ -4,7 +4,7 @@ import io.bkbn.kompendium.oas.common.ExternalDocumentation import io.bkbn.kompendium.oas.payload.Parameter class PutInfo private constructor( - override val request: RequestInfo, + override val request: RequestInfo?, override val errors: MutableList, override val response: ResponseInfo, override val tags: Set, @@ -26,7 +26,7 @@ class PutInfo private constructor( class Builder : MethodInfoWithRequest.Builder() { override fun build() = PutInfo( - request = request ?: error("request info must be present"), + request = request, errors = errors, response = response ?: error("response info must be present"), tags = tags, diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt index 3ec287986..a080b656c 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/util/Helpers.kt @@ -72,13 +72,15 @@ object Helpers { when (this) { is MethodInfoWithRequest -> { - SchemaGenerator.fromTypeOrUnit( - type = this.request.requestType, - cache = spec.components.schemas, - schemaConfigurator = schemaConfigurator, - enrichment = this.request.typeEnrichment, - )?.let { schema -> - spec.components.schemas[this.request.requestType.getSlug(this.request.typeEnrichment)] = schema + this.request?.let { reqInfo -> + SchemaGenerator.fromTypeOrUnit( + type = reqInfo.requestType, + cache = spec.components.schemas, + schemaConfigurator = schemaConfigurator, + enrichment = reqInfo.typeEnrichment, + )?.let { schema -> + spec.components.schemas[reqInfo.requestType.getSlug(reqInfo.typeEnrichment)] = schema + } } } @@ -121,15 +123,17 @@ object Helpers { ?.map { listOf(it).toMap() } ?.toMutableList(), requestBody = when (this) { - is MethodInfoWithRequest -> Request( - description = this.request.description, - content = this.request.requestType.toReferenceContent( - examples = this.request.examples, - mediaTypes = this.request.mediaTypes, - enrichment = this.request.typeEnrichment - ), - required = true - ) + is MethodInfoWithRequest -> this.request?.let { reqInfo -> + Request( + description = reqInfo.description, + content = reqInfo.requestType.toReferenceContent( + examples = reqInfo.examples, + mediaTypes = reqInfo.mediaTypes, + enrichment = reqInfo.typeEnrichment + ), + required = true + ) + } else -> null }, diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt index 759fbf80d..d15632440 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt @@ -48,6 +48,7 @@ import io.bkbn.kompendium.core.util.polymorphicCollectionResponse import io.bkbn.kompendium.core.util.polymorphicException import io.bkbn.kompendium.core.util.polymorphicMapResponse 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.reqRespExamples import io.bkbn.kompendium.core.util.requiredParams @@ -129,6 +130,9 @@ class KompendiumTest : DescribeSpec({ it("Can override media types") { 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() } + } } describe("Route Parsing") { it("Can parse a simple path and store it under the expected route") { diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/util/NotarizedOpenApi.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/util/NotarizedOpenApi.kt index 5351e3ba9..376da49e7 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/util/NotarizedOpenApi.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/util/NotarizedOpenApi.kt @@ -299,3 +299,19 @@ fun Routing.overrideMediaTypes() { } } } + +fun Routing.postNoReqBody() { + route("/no_req_body") { + install(NotarizedRoute()) { + post = PostInfo.builder { + summary(defaultPathSummary) + description(defaultPathDescription) + response { + responseType() + description("Cool response") + responseCode(HttpStatusCode.Created) + } + } + } + } +} diff --git a/core/src/test/resources/T0065__post_no_req_body.json b/core/src/test/resources/T0065__post_no_req_body.json new file mode 100644 index 000000000..1c6e55afe --- /dev/null +++ b/core/src/test/resources/T0065__post_no_req_body.json @@ -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": [] +} diff --git a/gradle.properties b/gradle.properties index 518bc7d24..d2153d4e0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Kompendium -project.version=3.12.0 +project.version=3.13.0 # Kotlin kotlin.code.style=official # Gradle