Repository: bkbnio/kompendium (kotlin)

Issue:
V3 forced all RequestInfo not null 
V2.3.5 allows nullable RequestInfo for Put, Patch and Post.
However, this change force all not null https://github.com/bkbnio/kompendium/pull/256.

From 

```
data class PutInfo<TParam, TReq, TResp>(
  val requestInfo: RequestInfo<TReq>?,
  override val responseInfo: ResponseInfo<TResp>,
  override val summary: String,
  override val description: String? = null,
  override val tags: Set<String> = emptySet(),
  override val deprecated: Boolean = false,
  override val securitySchemes: Set<String> = emptySet(),
  override val canThrow: Set<ExceptionInfo<*>> = emptySet(),
  override val parameterExamples: Set<ParameterExample> = emptySet(),
  override val operationId: String? = null
) : MethodInfo<TParam, TResp>
```
to ( newest code)

```
class PutInfo private constructor(
  override val request: RequestInfo,
  override val errors: MutableList<ResponseInfo>,
  override val response: ResponseInfo,
  override val tags: Set<String>,
  override val summary: String,
  override val description: String,
  override val externalDocumentation: ExternalDocumentation?,
  override val operationId: String?,
  override val deprecated: Boolean,
  override val parameters: List<Parameter>
) : MethodInfoWithRequest {

  companion object {
    fun builder(init: Builder.() -> Unit): PutInfo {
      val builder = Builder()
      builder.init()
      return builder.build()
    }
  }

  class Builder : MethodInfoWithRequest.Builder<PutInfo>() {
    override fun build() = PutInfo(
      request = request ?: error("request info must be present"),
      errors = errors,
      response = response ?: error("response info must be present"),
      tags = tags,
      summary = summary ?: error("Summary must be present"),
      description = description ?: error("Description must be present"),
      externalDocumentation = externalDocumentation,
      operationId = operationId,
      deprecated = deprecated,
      parameters = parameters
    )
  }
}
```

Can you help to make them nullable back? (A similar request here https://github.com/bkbnio/kompendium/issues/242)

Pull request:
# Description

Modifies post, put and patch info to not require a request body.  Passing `Unit` as type is still supported for backwards compatibility. 

Closes #411

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation 
- [ ] Chore

# How Has This Been Tested?

Added test

# Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] I have updated the CHANGELOG in the `Unreleased` section
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee1671feea..fd05fa3f0f 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 af4c177ef3..3bbb259d34 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<T : MethodInfoWithRequest> : MethodInfo.Builder<T>() {
     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 eabf4f7fb8..9cefdb424e 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<ResponseInfo>,
   override val response: ResponseInfo,
   override val tags: Set<String>,
@@ -26,7 +26,7 @@ class PatchInfo private constructor(
 
   class Builder : MethodInfoWithRequest.Builder<PatchInfo>() {
     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 d7a406fdc6..2020fd1763 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<ResponseInfo>,
   override val response: ResponseInfo,
   override val tags: Set<String>,
@@ -26,7 +26,7 @@ class PostInfo private constructor(
 
   class Builder : MethodInfoWithRequest.Builder<PostInfo>() {
     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 152c30b640..f4c508b715 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<ResponseInfo>,
   override val response: ResponseInfo,
   override val tags: Set<String>,
@@ -26,7 +26,7 @@ class PutInfo private constructor(
 
   class Builder : MethodInfoWithRequest.Builder<PutInfo>() {
     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 3ec287986e..a080b656c8 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/gradle.properties b/gradle.properties
index 518bc7d245..d2153d4e0b 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


Test patch:
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 759fbf80d2..d156324401 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 5351e3ba92..376da49e70 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<TestResponse>()
+          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 0000000000..1c6e55afe2
--- /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": []
+}