feat: added head, patch, and options methods (#132)

This commit is contained in:
Ryan Brink
2022-01-03 09:32:55 -05:00
committed by GitHub
parent f02f7ad211
commit 012db5ad26
12 changed files with 381 additions and 40 deletions

View File

@ -2,6 +2,7 @@
## Unreleased ## Unreleased
### Added ### Added
- Support for HTTP Patch, Head, and Options methods
### Changed ### Changed

View File

@ -1,5 +1,5 @@
# Kompendium # Kompendium
project.version=2.0.0-alpha project.version=2.0.0-beta
# Kotlin # Kotlin
kotlin.code.style=official kotlin.code.style=official
# Gradle # Gradle

View File

@ -5,6 +5,9 @@ import io.bkbn.kompendium.core.KompendiumPreFlight.methodNotarizationPreFlight
import io.bkbn.kompendium.core.MethodParser.parseMethodInfo import io.bkbn.kompendium.core.MethodParser.parseMethodInfo
import io.bkbn.kompendium.core.metadata.method.DeleteInfo 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.HeadInfo
import io.bkbn.kompendium.core.metadata.method.OptionsInfo
import io.bkbn.kompendium.core.metadata.method.PatchInfo
import io.bkbn.kompendium.core.metadata.method.PostInfo import io.bkbn.kompendium.core.metadata.method.PostInfo
import io.bkbn.kompendium.core.metadata.method.PutInfo import io.bkbn.kompendium.core.metadata.method.PutInfo
import io.bkbn.kompendium.oas.path.Path import io.bkbn.kompendium.oas.path.Path
@ -66,7 +69,7 @@ object Notarized {
} }
/** /**
* Notarization for an HTTP Delete request * Notarization for an HTTP PUT request
* @param TParam The class containing all parameter fields. Each field must be annotated with @[Param] * @param TParam The class containing all parameter fields. Each field must be annotated with @[Param]
* @param TReq Class detailing the expected API request body * @param TReq Class detailing the expected API request body
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
@ -87,7 +90,28 @@ object Notarized {
} }
/** /**
* Notarization for an HTTP POST request * Notarization for an HTTP PATCH request
* @param TParam The class containing all parameter fields. Each field must be annotated with @[Param]
* @param TReq Class detailing the expected API request body
* @param TResp Class detailing the expected API response
* @param info Route metadata
* @param postProcess Adds an optional callback hook to perform manual overrides on the generated [PathOperation]
*/
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPatch(
info: PatchInfo<TParam, TReq, TResp>,
postProcess: (PathOperation) -> PathOperation = { p -> p },
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
): Route = methodNotarizationPreFlight<TParam, TReq, TResp> { paramType, requestType, responseType ->
val feature = this.application.feature(Kompendium)
val path = calculateRoutePath()
feature.config.spec.paths.getOrPut(path) { Path() }
val baseInfo = parseMethodInfo(info, paramType, requestType, responseType, feature)
feature.config.spec.paths[path]?.patch = postProcess(baseInfo)
return method(HttpMethod.Patch) { handle(body) }
}
/**
* Notarization for an HTTP DELETE request
* @param TParam The class containing all parameter fields. Each field must be annotated with @[Param] * @param TParam The class containing all parameter fields. Each field must be annotated with @[Param]
* @param TResp Class detailing the expected API response * @param TResp Class detailing the expected API response
* @param info Route metadata * @param info Route metadata
@ -106,6 +130,45 @@ object Notarized {
return method(HttpMethod.Delete) { handle(body) } return method(HttpMethod.Delete) { handle(body) }
} }
/**
* Notarization for an HTTP HEAD request
* @param TParam The class containing all parameter fields. Each field must be annotated with @[Param]
* @param info Route metadata
* @param postProcess Adds an optional callback hook to perform manual overrides on the generated [PathOperation]
*/
inline fun <reified TParam : Any> Route.notarizedHead(
info: HeadInfo<TParam>,
postProcess: (PathOperation) -> PathOperation = { p -> p },
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = methodNotarizationPreFlight<TParam, Unit, Unit> { paramType, requestType, responseType ->
val feature = this.application.feature(Kompendium)
val path = calculateRoutePath()
feature.config.spec.paths.getOrPut(path) { Path() }
val baseInfo = parseMethodInfo(info, paramType, requestType, responseType, feature)
feature.config.spec.paths[path]?.head = postProcess(baseInfo)
return method(HttpMethod.Head) { handle(body) }
}
/**
* Notarization for an HTTP OPTION request
* @param TParam The class containing all parameter fields. Each field must be annotated with @[Param]
* @param TResp Class detailing the expected API response
* @param info Route metadata
* @param postProcess Adds an optional callback hook to perform manual overrides on the generated [PathOperation]
*/
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedOptions(
info: OptionsInfo<TParam, TResp>,
postProcess: (PathOperation) -> PathOperation = { p -> p },
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = methodNotarizationPreFlight<TParam, Unit, TResp> { paramType, requestType, responseType ->
val feature = this.application.feature(Kompendium)
val path = calculateRoutePath()
feature.config.spec.paths.getOrPut(path) { Path() }
val baseInfo = parseMethodInfo(info, paramType, requestType, responseType, feature)
feature.config.spec.paths[path]?.options = postProcess(baseInfo)
return method(HttpMethod.Options) { handle(body) }
}
/** /**
* Uses the built-in Ktor route path [Route.toString] but cuts out any meta route such as authentication... anything * Uses the built-in Ktor route path [Route.toString] but cuts out any meta route such as authentication... anything
* that matches the RegEx pattern `/\\(.+\\)` * that matches the RegEx pattern `/\\(.+\\)`

View File

@ -0,0 +1,16 @@
package io.bkbn.kompendium.core.metadata.method
import io.bkbn.kompendium.core.metadata.ExceptionInfo
import io.bkbn.kompendium.core.metadata.ResponseInfo
data class HeadInfo<TParam>(
override val responseInfo: ResponseInfo<Unit>,
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: Map<String, TParam> = emptyMap(),
override val operationId: String? = null
) : MethodInfo<TParam, Unit>

View File

@ -0,0 +1,16 @@
package io.bkbn.kompendium.core.metadata.method
import io.bkbn.kompendium.core.metadata.ExceptionInfo
import io.bkbn.kompendium.core.metadata.ResponseInfo
data class OptionsInfo<TParam, TResp>(
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: Map<String, TParam> = emptyMap(),
override val operationId: String? = null
) : MethodInfo<TParam, TResp>

View File

@ -0,0 +1,18 @@
package io.bkbn.kompendium.core.metadata.method
import io.bkbn.kompendium.core.metadata.ExceptionInfo
import io.bkbn.kompendium.core.metadata.RequestInfo
import io.bkbn.kompendium.core.metadata.ResponseInfo
data class PatchInfo<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: Map<String, TParam> = emptyMap(),
override val operationId: String? = null
) : MethodInfo<TParam, TResp>

View File

@ -27,6 +27,9 @@ import io.bkbn.kompendium.core.util.notarizedGetWithGenericErrorResponse
import io.bkbn.kompendium.core.util.notarizedGetWithMultipleThrowables import io.bkbn.kompendium.core.util.notarizedGetWithMultipleThrowables
import io.bkbn.kompendium.core.util.notarizedGetWithNotarizedException import io.bkbn.kompendium.core.util.notarizedGetWithNotarizedException
import io.bkbn.kompendium.core.util.notarizedGetWithPolymorphicErrorResponse import io.bkbn.kompendium.core.util.notarizedGetWithPolymorphicErrorResponse
import io.bkbn.kompendium.core.util.notarizedHeadModule
import io.bkbn.kompendium.core.util.notarizedOptionsModule
import io.bkbn.kompendium.core.util.notarizedPatchModule
import io.bkbn.kompendium.core.util.notarizedPostModule import io.bkbn.kompendium.core.util.notarizedPostModule
import io.bkbn.kompendium.core.util.notarizedPutModule import io.bkbn.kompendium.core.util.notarizedPutModule
import io.bkbn.kompendium.core.util.nullableField import io.bkbn.kompendium.core.util.nullableField
@ -55,56 +58,53 @@ import io.ktor.http.HttpStatusCode
class KompendiumTest : DescribeSpec({ class KompendiumTest : DescribeSpec({
describe("Notarized Open API Metadata Tests") { describe("Notarized Open API Metadata Tests") {
it("Can notarize a get request") { it("Can notarize a get request") {
// act
openApiTest("notarized_get.json") { notarizedGetModule() } openApiTest("notarized_get.json") { notarizedGetModule() }
} }
it("Can notarize a post request") { it("Can notarize a post request") {
// act
openApiTest("notarized_post.json") { notarizedPostModule() } openApiTest("notarized_post.json") { notarizedPostModule() }
} }
it("Can notarize a put request") { it("Can notarize a put request") {
// act
openApiTest("notarized_put.json") { notarizedPutModule() } openApiTest("notarized_put.json") { notarizedPutModule() }
} }
it("Can notarize a delete request") { it("Can notarize a delete request") {
// act
openApiTest("notarized_delete.json") { notarizedDeleteModule() } openApiTest("notarized_delete.json") { notarizedDeleteModule() }
} }
it("Can notarize a patch request") {
openApiTest("notarized_patch.json") { notarizedPatchModule() }
}
it("Can notarize a head request") {
openApiTest("notarized_head.json") { notarizedHeadModule() }
}
it("Can notarize an options request") {
openApiTest("notarized_options.json") { notarizedOptionsModule() }
}
it("Can notarize a complex type") { it("Can notarize a complex type") {
// act
openApiTest("complex_type.json") { complexType() } openApiTest("complex_type.json") { complexType() }
} }
it("Can notarize primitives") { it("Can notarize primitives") {
// act
openApiTest("notarized_primitives.json") { primitives() } openApiTest("notarized_primitives.json") { primitives() }
} }
it("Can notarize a top level list response") { it("Can notarize a top level list response") {
// act
openApiTest("response_list.json") { returnsList() } openApiTest("response_list.json") { returnsList() }
} }
it("Can notarize a route with non-required params") { it("Can notarize a route with non-required params") {
// act
openApiTest("non_required_params.json") { nonRequiredParamsGet() } openApiTest("non_required_params.json") { nonRequiredParamsGet() }
} }
} }
describe("Notarized Ktor Functionality Tests") { describe("Notarized Ktor Functionality Tests") {
it("Can notarized a get request and return the expected result") { it("Can notarized a get request and return the expected result") {
// act
apiFunctionalityTest("hey dude ‼️ congratz on the get request") { notarizedGetModule() } apiFunctionalityTest("hey dude ‼️ congratz on the get request") { notarizedGetModule() }
} }
it("Can notarize a post request and return the expected result") { it("Can notarize a post request and return the expected result") {
// act
apiFunctionalityTest( apiFunctionalityTest(
"hey dude ✌️ congratz on the post request", "hey dude ✌️ congratz on the post request",
httpMethod = HttpMethod.Post httpMethod = HttpMethod.Post
) { notarizedPostModule() } ) { notarizedPostModule() }
} }
it("Can notarize a put request and return the expected result") { it("Can notarize a put request and return the expected result") {
// act
apiFunctionalityTest("hey pal 🌝 whatcha doin' here?", httpMethod = HttpMethod.Put) { notarizedPutModule() } apiFunctionalityTest("hey pal 🌝 whatcha doin' here?", httpMethod = HttpMethod.Put) { notarizedPutModule() }
} }
it("Can notarize a delete request and return the expected result") { it("Can notarize a delete request and return the expected result") {
// act
apiFunctionalityTest( apiFunctionalityTest(
null, null,
httpMethod = HttpMethod.Delete, httpMethod = HttpMethod.Delete,
@ -112,59 +112,47 @@ class KompendiumTest : DescribeSpec({
) { notarizedDeleteModule() } ) { notarizedDeleteModule() }
} }
it("Can notarize the root route and return the expected result") { it("Can notarize the root route and return the expected result") {
// act
apiFunctionalityTest("☎️🏠🌲", "/") { rootModule() } apiFunctionalityTest("☎️🏠🌲", "/") { rootModule() }
} }
it("Can notarize a trailing slash route and return the expected result") { it("Can notarize a trailing slash route and return the expected result") {
// act
apiFunctionalityTest("🙀👾", "/test/") { trailingSlash() } apiFunctionalityTest("🙀👾", "/test/") { trailingSlash() }
} }
} }
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") {
// act
openApiTest("path_parser.json") { pathParsingTestModule() } openApiTest("path_parser.json") { pathParsingTestModule() }
} }
it("Can notarize the root route") { it("Can notarize the root route") {
// act
openApiTest("root_route.json") { rootModule() } openApiTest("root_route.json") { rootModule() }
} }
it("Can notarize a route under the root module without appending trailing slash") { it("Can notarize a route under the root module without appending trailing slash") {
// act
openApiTest("nested_under_root.json") { nestedUnderRootModule() } openApiTest("nested_under_root.json") { nestedUnderRootModule() }
} }
it("Can notarize a route with a trailing slash") { it("Can notarize a route with a trailing slash") {
// act
openApiTest("trailing_slash.json") { trailingSlash() } openApiTest("trailing_slash.json") { trailingSlash() }
} }
} }
describe("Exceptions") { describe("Exceptions") {
it("Can add an exception status code to a response") { it("Can add an exception status code to a response") {
// act
openApiTest("notarized_get_with_exception_response.json") { notarizedGetWithNotarizedException() } openApiTest("notarized_get_with_exception_response.json") { notarizedGetWithNotarizedException() }
} }
it("Can support multiple response codes") { it("Can support multiple response codes") {
// act
openApiTest("notarized_get_with_multiple_exception_responses.json") { notarizedGetWithMultipleThrowables() } openApiTest("notarized_get_with_multiple_exception_responses.json") { notarizedGetWithMultipleThrowables() }
} }
it("Can add a polymorphic exception response") { it("Can add a polymorphic exception response") {
// act
openApiTest("polymorphic_error_status_codes.json") { notarizedGetWithPolymorphicErrorResponse() } openApiTest("polymorphic_error_status_codes.json") { notarizedGetWithPolymorphicErrorResponse() }
} }
it("Can add a generic exception response") { it("Can add a generic exception response") {
// act
openApiTest("generic_exception.json") { notarizedGetWithGenericErrorResponse() } openApiTest("generic_exception.json") { notarizedGetWithGenericErrorResponse() }
} }
} }
describe("Examples") { describe("Examples") {
it("Can generate example response and request bodies") { it("Can generate example response and request bodies") {
// act
openApiTest("example_req_and_resp.json") { withExamples() } openApiTest("example_req_and_resp.json") { withExamples() }
} }
} }
describe("Defaults") { describe("Defaults") {
it("Can generate a default parameter values") { it("Can generate a default parameter values") {
// act
openApiTest("query_with_default_parameter.json") { withDefaultParameter() } openApiTest("query_with_default_parameter.json") { withDefaultParameter() }
} }
} }
@ -184,49 +172,38 @@ class KompendiumTest : DescribeSpec({
} }
describe("Polymorphism and Generics") { describe("Polymorphism and Generics") {
it("can generate a polymorphic response type") { it("can generate a polymorphic response type") {
// act
openApiTest("polymorphic_response.json") { polymorphicResponse() } openApiTest("polymorphic_response.json") { polymorphicResponse() }
} }
it("Can generate a collection with polymorphic response type") { it("Can generate a collection with polymorphic response type") {
// act
openApiTest("polymorphic_list_response.json") { polymorphicCollectionResponse() } openApiTest("polymorphic_list_response.json") { polymorphicCollectionResponse() }
} }
it("Can generate a map with a polymorphic response type") { it("Can generate a map with a polymorphic response type") {
// act
openApiTest("polymorphic_map_response.json") { polymorphicMapResponse() } openApiTest("polymorphic_map_response.json") { polymorphicMapResponse() }
} }
it("Can generate a polymorphic response from a sealed interface") { it("Can generate a polymorphic response from a sealed interface") {
// act
openApiTest("sealed_interface_response.json") { polymorphicInterfaceResponse() } openApiTest("sealed_interface_response.json") { polymorphicInterfaceResponse() }
} }
it("Can generate a response type with a generic type") { it("Can generate a response type with a generic type") {
// act
openApiTest("generic_response.json") { simpleGenericResponse() } openApiTest("generic_response.json") { simpleGenericResponse() }
} }
it("Can generate a polymorphic response type with generics") { it("Can generate a polymorphic response type with generics") {
// act
openApiTest("polymorphic_response_with_generics.json") { genericPolymorphicResponse() } openApiTest("polymorphic_response_with_generics.json") { genericPolymorphicResponse() }
} }
it("Can handle an absolutely psycho inheritance test") { it("Can handle an absolutely psycho inheritance test") {
// act
openApiTest("crazy_polymorphic_example.json") { genericPolymorphicResponseMultipleImpls() } openApiTest("crazy_polymorphic_example.json") { genericPolymorphicResponseMultipleImpls() }
} }
} }
describe("Miscellaneous") { describe("Miscellaneous") {
it("Can generate the necessary ReDoc home page") { it("Can generate the necessary ReDoc home page") {
// act
apiFunctionalityTest(getFileSnapshot("redoc.html"), "/docs") { returnsList() } apiFunctionalityTest(getFileSnapshot("redoc.html"), "/docs") { returnsList() }
} }
it("Can add an operation id to a notarized route") { it("Can add an operation id to a notarized route") {
// act
openApiTest("notarized_get_with_operation_id.json") { withOperationId() } openApiTest("notarized_get_with_operation_id.json") { withOperationId() }
} }
it("Can add an undeclared field") { it("Can add an undeclared field") {
// act
openApiTest("undeclared_field.json") { undeclaredType() } openApiTest("undeclared_field.json") { undeclaredType() }
} }
it("Can add a custom header parameter with a name override") { it("Can add a custom header parameter with a name override") {
// act
openApiTest("override_parameter_name.json") { headerParameter() } openApiTest("override_parameter_name.json") { headerParameter() }
} }
it("Can override field values via annotation") { it("Can override field values via annotation") {

View File

@ -2,6 +2,9 @@ package io.bkbn.kompendium.core.util
import io.bkbn.kompendium.core.Notarized.notarizedDelete import io.bkbn.kompendium.core.Notarized.notarizedDelete
import io.bkbn.kompendium.core.Notarized.notarizedGet import io.bkbn.kompendium.core.Notarized.notarizedGet
import io.bkbn.kompendium.core.Notarized.notarizedHead
import io.bkbn.kompendium.core.Notarized.notarizedOptions
import io.bkbn.kompendium.core.Notarized.notarizedPatch
import io.bkbn.kompendium.core.Notarized.notarizedPost import io.bkbn.kompendium.core.Notarized.notarizedPost
import io.bkbn.kompendium.core.Notarized.notarizedPut import io.bkbn.kompendium.core.Notarized.notarizedPut
import io.bkbn.kompendium.core.fixtures.Bibbity import io.bkbn.kompendium.core.fixtures.Bibbity
@ -105,6 +108,36 @@ fun Application.notarizedDeleteModule() {
} }
} }
fun Application.notarizedPatchModule() {
routing {
route("/test") {
notarizedPatch(TestResponseInfo.testPatchInfo) {
call.respondText { "hey dude ✌️ congratz on the patch request" }
}
}
}
}
fun Application.notarizedHeadModule() {
routing {
route("/test") {
notarizedHead(TestResponseInfo.testHeadInfo) {
call.response.status(HttpStatusCode.OK)
}
}
}
}
fun Application.notarizedOptionsModule() {
routing {
route("/test") {
notarizedOptions(TestResponseInfo.testOptionsInfo) {
call.response.status(HttpStatusCode.OK)
}
}
}
}
fun Application.notarizedPutModule() { fun Application.notarizedPutModule() {
routing { routing {
route("/test") { route("/test") {
@ -245,12 +278,12 @@ fun Application.withDefaultParameter() {
} }
} }
fun Application.withOperationId(){ fun Application.withOperationId() {
routing { routing {
route("/test") { route("/test") {
notarizedGet( notarizedGet(
info = TestResponseInfo.testGetInfo.copy(operationId = "getTest") info = TestResponseInfo.testGetInfo.copy(operationId = "getTest")
){ ) {
call.respond(HttpStatusCode.OK) call.respond(HttpStatusCode.OK)
} }
} }

View File

@ -0,0 +1,49 @@
{
"openapi": "3.0.3",
"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": {
"head": {
"tags": [],
"summary": "Test head endpoint",
"description": "head test 💀",
"parameters": [],
"responses": {
"200": {
"description": "great!"
}
},
"deprecated": false
}
}
},
"components": {
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,84 @@
{
"openapi": "3.0.3",
"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": {
"options": {
"tags": [],
"summary": "Test options",
"description": "endpoint of options",
"parameters": [
{
"name": "a",
"in": "path",
"schema": {
"type": "string"
},
"required": true,
"deprecated": false
},
{
"name": "aa",
"in": "query",
"schema": {
"format": "int32",
"type": "integer"
},
"required": true,
"deprecated": false
}
],
"responses": {
"200": {
"description": "nice",
"content": {
"application/json": {
"schema": {
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
],
"type": "object"
}
}
}
}
},
"deprecated": false
}
}
},
"components": {
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -0,0 +1,64 @@
{
"openapi": "3.0.3",
"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": {
"patch": {
"tags": [],
"summary": "Test patch endpoint",
"description": "patch your tests here!",
"parameters": [],
"responses": {
"201": {
"description": "A Successful Endeavor",
"content": {
"application/json": {
"schema": {
"properties": {
"c": {
"type": "string"
}
},
"required": [
"c"
],
"type": "object"
}
}
}
}
},
"deprecated": false
}
}
},
"components": {
"securitySchemes": {}
},
"security": [],
"tags": []
}

View File

@ -7,6 +7,9 @@ import io.bkbn.kompendium.core.metadata.RequestInfo
import io.bkbn.kompendium.core.metadata.ResponseInfo import io.bkbn.kompendium.core.metadata.ResponseInfo
import io.bkbn.kompendium.core.metadata.method.DeleteInfo 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.HeadInfo
import io.bkbn.kompendium.core.metadata.method.OptionsInfo
import io.bkbn.kompendium.core.metadata.method.PatchInfo
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import kotlin.reflect.typeOf import kotlin.reflect.typeOf
@ -15,6 +18,7 @@ object TestResponseInfo {
private val testGetListResponse = private val testGetListResponse =
ResponseInfo<List<TestResponse>>(HttpStatusCode.OK, "A Successful List-y Endeavor") ResponseInfo<List<TestResponse>>(HttpStatusCode.OK, "A Successful List-y Endeavor")
private val testPostResponse = ResponseInfo<TestCreatedResponse>(HttpStatusCode.Created, "A Successful Endeavor") private val testPostResponse = ResponseInfo<TestCreatedResponse>(HttpStatusCode.Created, "A Successful Endeavor")
private val testPatchResponse = ResponseInfo<TestResponse>(HttpStatusCode.Created, "A Successful Endeavor")
private val testPostResponseAgain = ResponseInfo<Boolean>(HttpStatusCode.Created, "A Successful Endeavor") private val testPostResponseAgain = ResponseInfo<Boolean>(HttpStatusCode.Created, "A Successful Endeavor")
private val testDeleteResponse = private val testDeleteResponse =
ResponseInfo<Unit>(HttpStatusCode.NoContent, "A Successful Endeavor", mediaTypes = emptyList()) ResponseInfo<Unit>(HttpStatusCode.NoContent, "A Successful Endeavor", mediaTypes = emptyList())
@ -75,6 +79,22 @@ object TestResponseInfo {
responseInfo = testPostResponse, responseInfo = testPostResponse,
requestInfo = complexRequest requestInfo = complexRequest
) )
val testPatchInfo = PatchInfo<Unit, TestRequest, TestResponse>(
summary = "Test patch endpoint",
description = "patch your tests here!",
responseInfo = testPatchResponse,
requestInfo = testRequest
)
val testHeadInfo = HeadInfo<Unit>(
summary = "Test head endpoint",
description = "head test 💀",
responseInfo = ResponseInfo(HttpStatusCode.OK, "great!")
)
val testOptionsInfo = OptionsInfo<TestParams, TestResponse>(
summary = "Test options",
description = "endpoint of options",
responseInfo = ResponseInfo(HttpStatusCode.OK, "nice")
)
val testPutInfoAlso = PutInfo<TestParams, TestRequest, TestCreatedResponse>( val testPutInfoAlso = PutInfo<TestParams, TestRequest, TestCreatedResponse>(
summary = "Test put endpoint", summary = "Test put endpoint",
description = "Put your tests here!", description = "Put your tests here!",