parameter support (#27)

This commit is contained in:
Ryan Brink
2021-04-17 16:20:37 -04:00
committed by GitHub
parent 81e24f96dc
commit ae4999483b
26 changed files with 340 additions and 64 deletions

View File

@ -1,5 +1,15 @@
# Changelog
## [0.4.0] - April 17th, 2021
### Added
- Basic Query and Path Parameter Support 🍻
### Changed
- No content workaround, flow will likely need refactoring for clarity.
## [0.3.0] - April 17th, 2021
### Changed

View File

@ -40,7 +40,6 @@ dependencies {
### Warning 🚨
Kompendium is still under active development ⚠️ There are a number of yet-to-be-implemented features, including
- Query and Path Parameters 🔍
- Tags 🏷
- Multiple Responses 📜
- Security Schemas 🔏
@ -70,11 +69,18 @@ meaning that swapping in a default Ktor route and a Kompendium `notarized` route
In general, Kompendium tries to limit the number of annotations that developers need to use in order to get an app
integrated.
Currently, there is only a single Kompendium annotation
Currently, the annotations used by Kompendium are as follows
- `KompendiumField`
- `PathParam`
- `QueryParam`
- `HeaderParam`
- `CookieParam`
The intended purpose is to offer field level overrides such as naming conventions (ie snake instead of camel).
The intended purpose of `KompendiumField` is to offer field level overrides such as naming conventions (ie snake instead of camel).
The 4 "param" annotations are to offer supplemental information in data classes that describe the set of parameters types
that a notarized route needs to analyze.
## Examples
@ -108,16 +114,16 @@ fun Application.mainModule() {
}
}
route("/single") {
notarizedGet<ExampleRequest, ExampleResponse>(testSingleGetInfo) {
notarizedGet<ExampleParams, ExampleResponse>(testSingleGetInfo) {
call.respondText("get single")
}
notarizedPost<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
notarizedPost<Unit, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
call.respondText("test post")
}
notarizedPut<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
call.respondText { "hey" }
}
notarizedDelete<Unit, DeleteResponse>(testSingleDeleteInfo) {
notarizedDelete<Unit, Unit>(testSingleDeleteInfo) {
call.respondText { "heya" }
}
}

View File

@ -65,7 +65,7 @@ complexity:
includePrivateDeclarations: false
ComplexMethod:
active: true
threshold: 15
threshold: 25
ignoreSingleWhenExpression: false
ignoreSimpleWhenEntries: false
ignoreNestingFunctions: false

View File

@ -1,5 +1,5 @@
# Kompendium
project.version=0.3.0
project.version=0.4.0
# Kotlin
kotlin.code.style=official
# Gradle

View File

@ -5,25 +5,39 @@ import io.ktor.http.HttpMethod
import io.ktor.routing.Route
import io.ktor.routing.method
import io.ktor.util.pipeline.PipelineInterceptor
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.full.findAnnotation
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField
import kotlin.reflect.typeOf
import org.leafygreens.kompendium.Kontent.generateKontent
import org.leafygreens.kompendium.Kontent.generateParameterKontent
import org.leafygreens.kompendium.annotations.CookieParam
import org.leafygreens.kompendium.annotations.HeaderParam
import org.leafygreens.kompendium.annotations.PathParam
import org.leafygreens.kompendium.annotations.QueryParam
import org.leafygreens.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo
import org.leafygreens.kompendium.models.meta.SchemaMap
import org.leafygreens.kompendium.models.oas.OpenApiSpec
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
import org.leafygreens.kompendium.models.oas.OpenApiSpecMediaType
import org.leafygreens.kompendium.models.oas.OpenApiSpecParameter
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItem
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
import org.leafygreens.kompendium.models.oas.OpenApiSpecReferenceObject
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaRef
import org.leafygreens.kompendium.util.Helpers.calculatePath
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
object Kompendium {
var cache: SchemaMap = emptyMap()
var openApiSpec = OpenApiSpec(
info = OpenApiSpecInfo(),
servers = mutableListOf(),
@ -34,46 +48,47 @@ object Kompendium {
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedGet(
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<Unit, TResp>() { requestType, responseType ->
): Route = notarizationPreFlight<TParam, Unit, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.get = info.parseMethodInfo(HttpMethod.Get, requestType, responseType)
openApiSpec.paths[path]?.get = info.parseMethodInfo(HttpMethod.Get, paramType, requestType, responseType)
return method(HttpMethod.Get) { handle(body) }
}
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPost(
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<TReq, TResp>() { requestType, responseType ->
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.post = info.parseMethodInfo(HttpMethod.Post, requestType, responseType)
openApiSpec.paths[path]?.post = info.parseMethodInfo(HttpMethod.Post, paramType, requestType, responseType)
return method(HttpMethod.Post) { handle(body) }
}
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPut(
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
): Route = notarizationPreFlight<TReq, TResp>() { requestType, responseType ->
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
val path = calculatePath()
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.put = info.parseMethodInfo(HttpMethod.Put, requestType, responseType)
openApiSpec.paths[path]?.put = info.parseMethodInfo(HttpMethod.Put, paramType, requestType, responseType)
return method(HttpMethod.Put) { handle(body) }
}
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedDelete(
info: MethodInfo,
noinline body: PipelineInterceptor<Unit, ApplicationCall>
): Route = notarizationPreFlight<Unit, TResp> { requestType, responseType ->
): Route = notarizationPreFlight<TParam, Unit, TResp> { paramType, requestType, responseType ->
val path = calculatePath()
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
openApiSpec.paths[path]?.delete = info.parseMethodInfo(HttpMethod.Delete, requestType, responseType)
openApiSpec.paths[path]?.delete = info.parseMethodInfo(HttpMethod.Delete, paramType, requestType, responseType)
return method(HttpMethod.Delete) { handle(body) }
}
// TODO here down is a mess, needs refactor once core functionality is in place
fun MethodInfo.parseMethodInfo(
method: HttpMethod,
paramType: KType,
requestType: KType,
responseType: KType
) = OpenApiSpecPathItemOperation(
@ -81,25 +96,27 @@ object Kompendium {
description = this.description,
tags = this.tags,
deprecated = this.deprecated,
responses = responseType.toSpec(responseInfo)?.let { mapOf(it) },
requestBody = if (method != HttpMethod.Get) requestType.toSpec(requestInfo) else null
parameters = paramType.toParameterSpec(),
responses = responseType.toResponseSpec(responseInfo)?.let { mapOf(it) },
requestBody = if (method != HttpMethod.Get) requestType.toRequestSpec(requestInfo) else null
)
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified TReq : Any, reified TResp : Any> notarizationPreFlight(
block: (KType, KType) -> Route
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> notarizationPreFlight(
block: (KType, KType, KType) -> Route
): Route {
val responseKontent = generateKontent<TResp>()
val requestKontent = generateKontent<TReq>()
openApiSpec.components.schemas.putAll(responseKontent)
openApiSpec.components.schemas.putAll(requestKontent)
cache = generateKontent<TResp>(cache)
cache = generateKontent<TReq>(cache)
cache = generateParameterKontent<TParam>(cache)
openApiSpec.components.schemas.putAll(cache)
val requestType = typeOf<TReq>()
val responseType = typeOf<TResp>()
return block.invoke(requestType, responseType)
val paramType = typeOf<TParam>()
return block.invoke(paramType, requestType, responseType)
}
// TODO These two lookin' real similar 👀 Combine?
private fun KType.toSpec(requestInfo: RequestInfo?): OpenApiSpecRequest? = when (this) {
private fun KType.toRequestSpec(requestInfo: RequestInfo?): OpenApiSpecRequest? = when (this) {
Unit::class -> null
else -> when (requestInfo) {
null -> null
@ -113,28 +130,62 @@ object Kompendium {
}
}
private fun KType.toSpec(responseInfo: ResponseInfo?): Pair<Int, OpenApiSpecResponse>? = when (this) {
private fun KType.toResponseSpec(responseInfo: ResponseInfo?): Pair<Int, OpenApiSpecResponse>? = when (this) {
Unit::class -> null // TODO Maybe not though? could be unit but 200 🤔
else -> when (responseInfo) {
null -> null // TODO again probably revisit this
else -> {
val content = responseInfo.mediaTypes.associateWith {
val ref = getReferenceSlug()
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
}
val specResponse = OpenApiSpecResponse(
description = responseInfo.description,
content = responseInfo.mediaTypes.associateWith {
val ref = getReferenceSlug()
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
}
content = content.ifEmpty { null }
)
Pair(responseInfo.status, specResponse)
}
}
}
// TODO God these annotations make this hideous... any way to improve?
private fun KType.toParameterSpec(): List<OpenApiSpecParameter> {
val clazz = classifier as KClass<*>
return clazz.memberProperties.map { prop ->
val field = prop.javaField?.type?.kotlin
?: error("Unable to parse field type from $prop")
val anny = prop.findAnnotation<PathParam>()
?: prop.findAnnotation<QueryParam>()
?: prop.findAnnotation<HeaderParam>()
?: prop.findAnnotation<CookieParam>()
?: error("Unable to find any relevant parameter specifier annotations on field ${prop.name}")
OpenApiSpecParameter(
name = prop.name,
`in` = when (anny) {
is PathParam -> "path"
is QueryParam -> "query"
is HeaderParam -> "header"
is CookieParam -> "cookie"
else -> error("should not be reachable")
},
schema = OpenApiSpecSchemaRef(field.getReferenceSlug(prop)),
description = when (anny) {
is PathParam -> anny.description.ifBlank { null }
is QueryParam -> anny.description.ifBlank { null }
is HeaderParam -> anny.description.ifBlank { null }
is CookieParam -> anny.description.ifBlank { null }
else -> error("should not be reachable")
}
)
}
}
internal fun resetSchema() {
openApiSpec = OpenApiSpec(
info = OpenApiSpecInfo(),
servers = mutableListOf(),
paths = mutableMapOf()
)
cache = emptyMap()
}
}

View File

@ -33,6 +33,15 @@ object Kontent {
return generateKTypeKontent(kontentType, cache)
}
@OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> generateParameterKontent(
cache: SchemaMap = emptyMap()
): SchemaMap {
val kontentType = typeOf<T>()
return generateKTypeKontent(kontentType, cache)
.filterNot { (slug, _) -> slug == (kontentType.classifier as KClass<*>).simpleName }
}
fun generateKTypeKontent(
type: KType,
cache: SchemaMap = emptyMap()

View File

@ -0,0 +1,5 @@
package org.leafygreens.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class CookieParam(val description: String = "")

View File

@ -0,0 +1,5 @@
package org.leafygreens.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class HeaderParam(val description: String = "")

View File

@ -0,0 +1,5 @@
package org.leafygreens.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class PathParam(val description: String = "")

View File

@ -0,0 +1,5 @@
package org.leafygreens.kompendium.annotations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class QueryParam(val description: String = "")

View File

@ -24,13 +24,13 @@ data class OpenApiSpecHeader(
data class OpenApiSpecParameter(
val name: String,
val `in`: String, // TODO Enum? "query", "header", "path" or "cookie"
val description: String?,
val schema: OpenApiSpecSchema,
val description: String? = null,
val required: Boolean = true,
val deprecated: Boolean = false,
val allowEmptyValue: Boolean = false,
val allowEmptyValue: Boolean? = null,
val style: String? = null,
val explode: Boolean? = false,
val schema: OpenApiSpecSchema? = null
val explode: Boolean? = null
) : OpenApiSpecReferencable()
data class OpenApiSpecRequest(

View File

@ -311,7 +311,7 @@ internal class KompendiumTest {
private companion object {
val testGetResponse = ResponseInfo(KompendiumHttpCodes.OK, "A Successful Endeavor")
val testPostResponse = ResponseInfo(KompendiumHttpCodes.CREATED, "A Successful Endeavor")
val testDeleteResponse = ResponseInfo(KompendiumHttpCodes.NO_CONTENT, "A Successful Endeavor")
val testDeleteResponse = ResponseInfo(KompendiumHttpCodes.NO_CONTENT, "A Successful Endeavor", mediaTypes = emptyList())
val testRequest = RequestInfo("A Test request")
val testGetInfo = MethodInfo("Another get test", "testing more", testGetResponse)
val testPostInfo = MethodInfo("Test post endpoint", "Post your tests here!", testPostResponse, testRequest)
@ -351,7 +351,7 @@ internal class KompendiumTest {
private fun Application.notarizedDeleteModule() {
routing {
route("/test") {
notarizedDelete<TestParams, TestDeleteResponse>(testDeleteInfo) {
notarizedDelete<TestParams, Unit>(testDeleteInfo) {
call.respond(HttpStatusCode.NoContent)
}
}

View File

@ -4,9 +4,11 @@ import java.util.UUID
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import org.leafygreens.kompendium.Kontent.generateKontent
import org.leafygreens.kompendium.Kontent.generateParameterKontent
import org.leafygreens.kompendium.models.oas.DictionarySchema
import org.leafygreens.kompendium.models.oas.FormatSchema
import org.leafygreens.kompendium.models.oas.ObjectSchema
@ -173,4 +175,15 @@ internal class KontentTest {
assertEquals(ReferencedSchema("#/components/schemas/CrazyItem"), rs)
}
@Test
fun `Parameter kontent filters out top level declaration`() {
// do
val result = generateParameterKontent<TestSimpleModel>()
// expect
assertNotNull(result)
assertEquals(2, result.count())
assertFalse { result.containsKey(TestSimpleModel::class.simpleName) }
}
}

View File

@ -2,6 +2,8 @@ package org.leafygreens.kompendium.util
import java.util.UUID
import org.leafygreens.kompendium.annotations.KompendiumField
import org.leafygreens.kompendium.annotations.PathParam
import org.leafygreens.kompendium.annotations.QueryParam
data class TestSimpleModel(val a: String, val b: Int)
@ -17,7 +19,10 @@ data class TestSimpleWithEnumList(val a: Double, val b: List<SimpleEnum>)
data class TestInvalidMap(val a: Map<Int, TestSimpleModel>)
data class TestParams(val a: String, val aa: Int)
data class TestParams(
@PathParam val a: String,
@QueryParam val aa: Int
)
data class TestNested(val nesty: String)

View File

@ -28,6 +28,7 @@
"tags" : [ ],
"summary" : "Test put endpoint",
"description" : "Put your tests here!",
"parameters" : [ ],
"requestBody" : {
"description" : "A Test request",
"content" : {

View File

@ -28,16 +28,26 @@
"tags" : [ ],
"summary" : "Test delete endpoint",
"description" : "testing my deletes",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"204" : {
"description" : "A Successful Endeavor",
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/TestDeleteResponse"
}
}
}
"description" : "A Successful Endeavor"
}
},
"deprecated" : false
@ -46,9 +56,12 @@
},
"components" : {
"schemas" : {
"TestDeleteResponse" : {
"properties" : { },
"type" : "object"
"String" : {
"type" : "string"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Another get test",
"description" : "testing more",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"200" : {
"description" : "A Successful Endeavor",
@ -56,6 +73,10 @@
}
},
"type" : "object"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Test post endpoint",
"description" : "Post your tests here!",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"requestBody" : {
"description" : "A Test request",
"content" : {

View File

@ -28,6 +28,7 @@
"tags" : [ ],
"summary" : "Test put endpoint",
"description" : "Put your tests here!",
"parameters" : [ ],
"requestBody" : {
"description" : "A Test request",
"content" : {

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Test put endpoint",
"description" : "Put your tests here!",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"requestBody" : {
"description" : "A Test request",
"content" : {

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Another get test",
"description" : "testing more",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"200" : {
"description" : "A Successful Endeavor",
@ -56,6 +73,10 @@
}
},
"type" : "object"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -103,12 +103,6 @@
"parameters" : [ {
"name" : "status",
"in" : "query",
"description" : "Status values that need to be considered for filter",
"required" : true,
"deprecated" : false,
"allowEmptyValue" : false,
"style" : "form",
"explode" : true,
"schema" : {
"items" : {
"default" : "available",
@ -116,7 +110,12 @@
"type" : "string"
},
"type" : "array"
}
},
"description" : "Status values that need to be considered for filter",
"required" : true,
"deprecated" : false,
"style" : "form",
"explode" : true
} ],
"responses" : {
"200" : {

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Another get test",
"description" : "testing more",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"200" : {
"description" : "A Successful Endeavor",
@ -62,6 +79,10 @@
"$ref" : "#/components/schemas/TestResponse"
},
"type" : "array"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Another get test",
"description" : "testing more",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"200" : {
"description" : "A Successful Endeavor",
@ -56,6 +73,10 @@
}
},
"type" : "object"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -28,6 +28,23 @@
"tags" : [ ],
"summary" : "Another get test",
"description" : "testing more",
"parameters" : [ {
"name" : "a",
"in" : "path",
"schema" : {
"$ref" : "#/components/schemas/String"
},
"required" : true,
"deprecated" : false
}, {
"name" : "aa",
"in" : "query",
"schema" : {
"$ref" : "#/components/schemas/Int"
},
"required" : true,
"deprecated" : false
} ],
"responses" : {
"200" : {
"description" : "A Successful Endeavor",
@ -56,6 +73,10 @@
}
},
"type" : "object"
},
"Int" : {
"format" : "int32",
"type" : "integer"
}
},
"securitySchemes" : { }

View File

@ -31,6 +31,8 @@ import org.leafygreens.kompendium.Kompendium.notarizedPost
import org.leafygreens.kompendium.Kompendium.notarizedPut
import org.leafygreens.kompendium.Kompendium.openApiSpec
import org.leafygreens.kompendium.annotations.KompendiumField
import org.leafygreens.kompendium.annotations.PathParam
import org.leafygreens.kompendium.annotations.QueryParam
import org.leafygreens.kompendium.models.meta.MethodInfo
import org.leafygreens.kompendium.models.meta.RequestInfo
import org.leafygreens.kompendium.models.meta.ResponseInfo
@ -70,16 +72,16 @@ fun Application.mainModule() {
}
}
route("/single") {
notarizedGet<ExampleRequest, ExampleResponse>(testSingleGetInfo) {
notarizedGet<Unit, ExampleResponse>(testSingleGetInfo) {
call.respondText("get single")
}
notarizedPost<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
notarizedPost<Unit, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
call.respondText("test post")
}
notarizedPut<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
notarizedPut<JustQuery, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
call.respondText { "hey" }
}
notarizedDelete<Unit, DeleteResponse>(testSingleDeleteInfo) {
notarizedDelete<Unit, Unit>(testSingleDeleteInfo) {
call.respondText { "heya" }
}
}
@ -87,12 +89,18 @@ fun Application.mainModule() {
}
}
data class ExampleParams(val a: String, val aa: Int)
data class ExampleParams(
@PathParam val id: Int,
@QueryParam val name: String
)
data class JustQuery(
@QueryParam val potato: Boolean,
@QueryParam val tomato: String
)
data class ExampleNested(val nesty: String)
object DeleteResponse
data class ExampleRequest(
@KompendiumField(name = "field_name")
val fieldName: ExampleNested,
@ -150,7 +158,8 @@ object KompendiumTOC {
description = "testing my deletes",
responseInfo = ResponseInfo(
status = KompendiumHttpCodes.NO_CONTENT,
description = "Signifies that your item was deleted succesfully"
description = "Signifies that your item was deleted successfully",
mediaTypes = emptyList()
)
)
}