From 588e52c9dfc54c2ce7d18e329ba0063c29522708 Mon Sep 17 00:00:00 2001 From: NovolMob <60779683+NovolMob@users.noreply.github.com> Date: Mon, 22 May 2023 16:39:04 +0300 Subject: [PATCH] fix: allow for request bodies to be marked as required=false (#470) --- CHANGELOG.md | 4 +- .../kompendium/core/metadata/RequestInfo.kt | 11 +- .../io/bkbn/kompendium/core/util/Helpers.kt | 2 +- .../io/bkbn/kompendium/core/KompendiumTest.kt | 4 + .../io/bkbn/kompendium/core/util/Examples.kt | 27 ++++ .../T0069__example_optional_req.json | 136 ++++++++++++++++++ 6 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 core/src/test/resources/T0069__example_optional_req.json diff --git a/CHANGELOG.md b/CHANGELOG.md index f17cac84b..2da2708ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,9 @@ ### Added -### Changed +- Added `required` parameter in request info builder. -- Route generation with parameters doesn`t add parameters to the path. +### Changed ### Remove diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/RequestInfo.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/RequestInfo.kt index 35af63231..07233a8fd 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/RequestInfo.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/metadata/RequestInfo.kt @@ -10,7 +10,8 @@ class RequestInfo private constructor( val typeEnrichment: TypeEnrichment<*>?, val description: String, val examples: Map?, - val mediaTypes: Set + val mediaTypes: Set, + val required: Boolean ) { companion object { @@ -27,6 +28,11 @@ class RequestInfo private constructor( private var description: String? = null private var examples: Map? = null private var mediaTypes: Set? = null + private var required: Boolean? = null + + fun required(r: Boolean) = apply { + this.required = r + } fun requestType(t: KType) = apply { this.requestType = t @@ -56,7 +62,8 @@ class RequestInfo private constructor( description = description ?: error("Description must be present"), typeEnrichment = typeEnrichment, examples = examples, - mediaTypes = mediaTypes ?: setOf("application/json") + mediaTypes = mediaTypes ?: setOf("application/json"), + required = required ?: true ) } } 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 4075fe67c..e9bb4a09d 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 @@ -131,7 +131,7 @@ object Helpers { mediaTypes = reqInfo.mediaTypes, enrichment = reqInfo.typeEnrichment ), - required = true + required = reqInfo.required ) } 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 3c4811082..d37abd22d 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/KompendiumTest.kt @@ -52,6 +52,7 @@ 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.optionalReqExample import io.bkbn.kompendium.core.util.requiredParams import io.bkbn.kompendium.core.util.responseHeaders import io.bkbn.kompendium.core.util.returnsList @@ -178,6 +179,9 @@ class KompendiumTest : DescribeSpec({ it("Can describe example parameters") { openApiTestAllSerializers("T0021__example_parameters.json") { exampleParams() } } + it("Can generate example optional request body") { + openApiTestAllSerializers("T0069__example_optional_req.json") { optionalReqExample() } + } } describe("Defaults") { it("Can generate a default parameter value") { diff --git a/core/src/test/kotlin/io/bkbn/kompendium/core/util/Examples.kt b/core/src/test/kotlin/io/bkbn/kompendium/core/util/Examples.kt index e98351faf..0a7da3406 100644 --- a/core/src/test/kotlin/io/bkbn/kompendium/core/util/Examples.kt +++ b/core/src/test/kotlin/io/bkbn/kompendium/core/util/Examples.kt @@ -55,3 +55,30 @@ fun Routing.exampleParams() = basicGetGenerator( ) ) ) + +fun Routing.optionalReqExample() { + route(rootPath) { + install(NotarizedRoute()) { + post = PostInfo.builder { + summary(defaultPathSummary) + description(defaultPathDescription) + request { + description(defaultRequestDescription) + requestType() + examples( + "Testerina" to TestRequest(TestNested("asdf"), 1.5, emptyList()) + ) + required(false) + } + response { + description(defaultResponseDescription) + responseCode(HttpStatusCode.OK) + responseType() + examples( + "Testerino" to TestResponse("Heya") + ) + } + } + } + } +} diff --git a/core/src/test/resources/T0069__example_optional_req.json b/core/src/test/resources/T0069__example_optional_req.json new file mode 100644 index 000000000..04c200d0c --- /dev/null +++ b/core/src/test/resources/T0069__example_optional_req.json @@ -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": [] +}