parameter support (#27)
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# 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
|
## [0.3.0] - April 17th, 2021
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
18
README.md
18
README.md
@ -40,7 +40,6 @@ dependencies {
|
|||||||
### Warning 🚨
|
### Warning 🚨
|
||||||
Kompendium is still under active development ⚠️ There are a number of yet-to-be-implemented features, including
|
Kompendium is still under active development ⚠️ There are a number of yet-to-be-implemented features, including
|
||||||
|
|
||||||
- Query and Path Parameters 🔍
|
|
||||||
- Tags 🏷
|
- Tags 🏷
|
||||||
- Multiple Responses 📜
|
- Multiple Responses 📜
|
||||||
- Security Schemas 🔏
|
- 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
|
In general, Kompendium tries to limit the number of annotations that developers need to use in order to get an app
|
||||||
integrated.
|
integrated.
|
||||||
|
|
||||||
Currently, there is only a single Kompendium annotation
|
Currently, the annotations used by Kompendium are as follows
|
||||||
|
|
||||||
- `KompendiumField`
|
- `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
|
## Examples
|
||||||
|
|
||||||
@ -108,16 +114,16 @@ fun Application.mainModule() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
route("/single") {
|
route("/single") {
|
||||||
notarizedGet<ExampleRequest, ExampleResponse>(testSingleGetInfo) {
|
notarizedGet<ExampleParams, ExampleResponse>(testSingleGetInfo) {
|
||||||
call.respondText("get single")
|
call.respondText("get single")
|
||||||
}
|
}
|
||||||
notarizedPost<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
|
notarizedPost<Unit, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
|
||||||
call.respondText("test post")
|
call.respondText("test post")
|
||||||
}
|
}
|
||||||
notarizedPut<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
|
notarizedPut<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
|
||||||
call.respondText { "hey" }
|
call.respondText { "hey" }
|
||||||
}
|
}
|
||||||
notarizedDelete<Unit, DeleteResponse>(testSingleDeleteInfo) {
|
notarizedDelete<Unit, Unit>(testSingleDeleteInfo) {
|
||||||
call.respondText { "heya" }
|
call.respondText { "heya" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ complexity:
|
|||||||
includePrivateDeclarations: false
|
includePrivateDeclarations: false
|
||||||
ComplexMethod:
|
ComplexMethod:
|
||||||
active: true
|
active: true
|
||||||
threshold: 15
|
threshold: 25
|
||||||
ignoreSingleWhenExpression: false
|
ignoreSingleWhenExpression: false
|
||||||
ignoreSimpleWhenEntries: false
|
ignoreSimpleWhenEntries: false
|
||||||
ignoreNestingFunctions: false
|
ignoreNestingFunctions: false
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Kompendium
|
# Kompendium
|
||||||
project.version=0.3.0
|
project.version=0.4.0
|
||||||
# Kotlin
|
# Kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
# Gradle
|
# Gradle
|
||||||
|
@ -5,25 +5,39 @@ import io.ktor.http.HttpMethod
|
|||||||
import io.ktor.routing.Route
|
import io.ktor.routing.Route
|
||||||
import io.ktor.routing.method
|
import io.ktor.routing.method
|
||||||
import io.ktor.util.pipeline.PipelineInterceptor
|
import io.ktor.util.pipeline.PipelineInterceptor
|
||||||
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
import kotlin.reflect.full.findAnnotation
|
||||||
|
import kotlin.reflect.full.memberProperties
|
||||||
|
import kotlin.reflect.jvm.javaField
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
import org.leafygreens.kompendium.Kontent.generateKontent
|
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.MethodInfo
|
||||||
import org.leafygreens.kompendium.models.meta.RequestInfo
|
import org.leafygreens.kompendium.models.meta.RequestInfo
|
||||||
import org.leafygreens.kompendium.models.meta.ResponseInfo
|
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.OpenApiSpec
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecInfo
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecMediaType
|
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.OpenApiSpecPathItem
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecPathItemOperation
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecReferenceObject
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecReferenceObject
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecRequest
|
||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
|
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.calculatePath
|
||||||
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
|
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
|
||||||
|
|
||||||
object Kompendium {
|
object Kompendium {
|
||||||
|
|
||||||
|
var cache: SchemaMap = emptyMap()
|
||||||
|
|
||||||
var openApiSpec = OpenApiSpec(
|
var openApiSpec = OpenApiSpec(
|
||||||
info = OpenApiSpecInfo(),
|
info = OpenApiSpecInfo(),
|
||||||
servers = mutableListOf(),
|
servers = mutableListOf(),
|
||||||
@ -34,46 +48,47 @@ object Kompendium {
|
|||||||
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedGet(
|
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedGet(
|
||||||
info: MethodInfo,
|
info: MethodInfo,
|
||||||
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
||||||
): Route = notarizationPreFlight<Unit, TResp>() { requestType, responseType ->
|
): Route = notarizationPreFlight<TParam, Unit, TResp>() { paramType, requestType, responseType ->
|
||||||
val path = calculatePath()
|
val path = calculatePath()
|
||||||
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
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) }
|
return method(HttpMethod.Get) { handle(body) }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPost(
|
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPost(
|
||||||
info: MethodInfo,
|
info: MethodInfo,
|
||||||
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
||||||
): Route = notarizationPreFlight<TReq, TResp>() { requestType, responseType ->
|
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
|
||||||
val path = calculatePath()
|
val path = calculatePath()
|
||||||
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
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) }
|
return method(HttpMethod.Post) { handle(body) }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPut(
|
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> Route.notarizedPut(
|
||||||
info: MethodInfo,
|
info: MethodInfo,
|
||||||
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>,
|
||||||
): Route = notarizationPreFlight<TReq, TResp>() { requestType, responseType ->
|
): Route = notarizationPreFlight<TParam, TReq, TResp>() { paramType, requestType, responseType ->
|
||||||
val path = calculatePath()
|
val path = calculatePath()
|
||||||
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
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) }
|
return method(HttpMethod.Put) { handle(body) }
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedDelete(
|
inline fun <reified TParam : Any, reified TResp : Any> Route.notarizedDelete(
|
||||||
info: MethodInfo,
|
info: MethodInfo,
|
||||||
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
noinline body: PipelineInterceptor<Unit, ApplicationCall>
|
||||||
): Route = notarizationPreFlight<Unit, TResp> { requestType, responseType ->
|
): Route = notarizationPreFlight<TParam, Unit, TResp> { paramType, requestType, responseType ->
|
||||||
val path = calculatePath()
|
val path = calculatePath()
|
||||||
openApiSpec.paths.getOrPut(path) { OpenApiSpecPathItem() }
|
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) }
|
return method(HttpMethod.Delete) { handle(body) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO here down is a mess, needs refactor once core functionality is in place
|
// TODO here down is a mess, needs refactor once core functionality is in place
|
||||||
fun MethodInfo.parseMethodInfo(
|
fun MethodInfo.parseMethodInfo(
|
||||||
method: HttpMethod,
|
method: HttpMethod,
|
||||||
|
paramType: KType,
|
||||||
requestType: KType,
|
requestType: KType,
|
||||||
responseType: KType
|
responseType: KType
|
||||||
) = OpenApiSpecPathItemOperation(
|
) = OpenApiSpecPathItemOperation(
|
||||||
@ -81,25 +96,27 @@ object Kompendium {
|
|||||||
description = this.description,
|
description = this.description,
|
||||||
tags = this.tags,
|
tags = this.tags,
|
||||||
deprecated = this.deprecated,
|
deprecated = this.deprecated,
|
||||||
responses = responseType.toSpec(responseInfo)?.let { mapOf(it) },
|
parameters = paramType.toParameterSpec(),
|
||||||
requestBody = if (method != HttpMethod.Get) requestType.toSpec(requestInfo) else null
|
responses = responseType.toResponseSpec(responseInfo)?.let { mapOf(it) },
|
||||||
|
requestBody = if (method != HttpMethod.Get) requestType.toRequestSpec(requestInfo) else null
|
||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
inline fun <reified TReq : Any, reified TResp : Any> notarizationPreFlight(
|
inline fun <reified TParam : Any, reified TReq : Any, reified TResp : Any> notarizationPreFlight(
|
||||||
block: (KType, KType) -> Route
|
block: (KType, KType, KType) -> Route
|
||||||
): Route {
|
): Route {
|
||||||
val responseKontent = generateKontent<TResp>()
|
cache = generateKontent<TResp>(cache)
|
||||||
val requestKontent = generateKontent<TReq>()
|
cache = generateKontent<TReq>(cache)
|
||||||
openApiSpec.components.schemas.putAll(responseKontent)
|
cache = generateParameterKontent<TParam>(cache)
|
||||||
openApiSpec.components.schemas.putAll(requestKontent)
|
openApiSpec.components.schemas.putAll(cache)
|
||||||
val requestType = typeOf<TReq>()
|
val requestType = typeOf<TReq>()
|
||||||
val responseType = typeOf<TResp>()
|
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?
|
// 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
|
Unit::class -> null
|
||||||
else -> when (requestInfo) {
|
else -> when (requestInfo) {
|
||||||
null -> null
|
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 🤔
|
Unit::class -> null // TODO Maybe not though? could be unit but 200 🤔
|
||||||
else -> when (responseInfo) {
|
else -> when (responseInfo) {
|
||||||
null -> null // TODO again probably revisit this
|
null -> null // TODO again probably revisit this
|
||||||
else -> {
|
else -> {
|
||||||
|
val content = responseInfo.mediaTypes.associateWith {
|
||||||
|
val ref = getReferenceSlug()
|
||||||
|
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
|
||||||
|
}
|
||||||
val specResponse = OpenApiSpecResponse(
|
val specResponse = OpenApiSpecResponse(
|
||||||
description = responseInfo.description,
|
description = responseInfo.description,
|
||||||
content = responseInfo.mediaTypes.associateWith {
|
content = content.ifEmpty { null }
|
||||||
val ref = getReferenceSlug()
|
|
||||||
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
Pair(responseInfo.status, specResponse)
|
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() {
|
internal fun resetSchema() {
|
||||||
openApiSpec = OpenApiSpec(
|
openApiSpec = OpenApiSpec(
|
||||||
info = OpenApiSpecInfo(),
|
info = OpenApiSpecInfo(),
|
||||||
servers = mutableListOf(),
|
servers = mutableListOf(),
|
||||||
paths = mutableMapOf()
|
paths = mutableMapOf()
|
||||||
)
|
)
|
||||||
|
cache = emptyMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,15 @@ object Kontent {
|
|||||||
return generateKTypeKontent(kontentType, cache)
|
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(
|
fun generateKTypeKontent(
|
||||||
type: KType,
|
type: KType,
|
||||||
cache: SchemaMap = emptyMap()
|
cache: SchemaMap = emptyMap()
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
|
annotation class CookieParam(val description: String = "")
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
|
annotation class HeaderParam(val description: String = "")
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
|
annotation class PathParam(val description: String = "")
|
@ -0,0 +1,5 @@
|
|||||||
|
package org.leafygreens.kompendium.annotations
|
||||||
|
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@Target(AnnotationTarget.PROPERTY)
|
||||||
|
annotation class QueryParam(val description: String = "")
|
@ -24,13 +24,13 @@ data class OpenApiSpecHeader(
|
|||||||
data class OpenApiSpecParameter(
|
data class OpenApiSpecParameter(
|
||||||
val name: String,
|
val name: String,
|
||||||
val `in`: String, // TODO Enum? "query", "header", "path" or "cookie"
|
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 required: Boolean = true,
|
||||||
val deprecated: Boolean = false,
|
val deprecated: Boolean = false,
|
||||||
val allowEmptyValue: Boolean = false,
|
val allowEmptyValue: Boolean? = null,
|
||||||
val style: String? = null,
|
val style: String? = null,
|
||||||
val explode: Boolean? = false,
|
val explode: Boolean? = null
|
||||||
val schema: OpenApiSpecSchema? = null
|
|
||||||
) : OpenApiSpecReferencable()
|
) : OpenApiSpecReferencable()
|
||||||
|
|
||||||
data class OpenApiSpecRequest(
|
data class OpenApiSpecRequest(
|
||||||
|
@ -311,7 +311,7 @@ internal class KompendiumTest {
|
|||||||
private companion object {
|
private companion object {
|
||||||
val testGetResponse = ResponseInfo(KompendiumHttpCodes.OK, "A Successful Endeavor")
|
val testGetResponse = ResponseInfo(KompendiumHttpCodes.OK, "A Successful Endeavor")
|
||||||
val testPostResponse = ResponseInfo(KompendiumHttpCodes.CREATED, "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 testRequest = RequestInfo("A Test request")
|
||||||
val testGetInfo = MethodInfo("Another get test", "testing more", testGetResponse)
|
val testGetInfo = MethodInfo("Another get test", "testing more", testGetResponse)
|
||||||
val testPostInfo = MethodInfo("Test post endpoint", "Post your tests here!", testPostResponse, testRequest)
|
val testPostInfo = MethodInfo("Test post endpoint", "Post your tests here!", testPostResponse, testRequest)
|
||||||
@ -351,7 +351,7 @@ internal class KompendiumTest {
|
|||||||
private fun Application.notarizedDeleteModule() {
|
private fun Application.notarizedDeleteModule() {
|
||||||
routing {
|
routing {
|
||||||
route("/test") {
|
route("/test") {
|
||||||
notarizedDelete<TestParams, TestDeleteResponse>(testDeleteInfo) {
|
notarizedDelete<TestParams, Unit>(testDeleteInfo) {
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,11 @@ import java.util.UUID
|
|||||||
import kotlin.test.Test
|
import kotlin.test.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFailsWith
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
import org.leafygreens.kompendium.Kontent.generateKontent
|
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.DictionarySchema
|
||||||
import org.leafygreens.kompendium.models.oas.FormatSchema
|
import org.leafygreens.kompendium.models.oas.FormatSchema
|
||||||
import org.leafygreens.kompendium.models.oas.ObjectSchema
|
import org.leafygreens.kompendium.models.oas.ObjectSchema
|
||||||
@ -173,4 +175,15 @@ internal class KontentTest {
|
|||||||
assertEquals(ReferencedSchema("#/components/schemas/CrazyItem"), rs)
|
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) }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package org.leafygreens.kompendium.util
|
|||||||
|
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumField
|
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)
|
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 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)
|
data class TestNested(val nesty: String)
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Test put endpoint",
|
"summary" : "Test put endpoint",
|
||||||
"description" : "Put your tests here!",
|
"description" : "Put your tests here!",
|
||||||
|
"parameters" : [ ],
|
||||||
"requestBody" : {
|
"requestBody" : {
|
||||||
"description" : "A Test request",
|
"description" : "A Test request",
|
||||||
"content" : {
|
"content" : {
|
||||||
|
@ -28,16 +28,26 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Test delete endpoint",
|
"summary" : "Test delete endpoint",
|
||||||
"description" : "testing my deletes",
|
"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" : {
|
"responses" : {
|
||||||
"204" : {
|
"204" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor"
|
||||||
"content" : {
|
|
||||||
"application/json" : {
|
|
||||||
"schema" : {
|
|
||||||
"$ref" : "#/components/schemas/TestDeleteResponse"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"deprecated" : false
|
"deprecated" : false
|
||||||
@ -46,9 +56,12 @@
|
|||||||
},
|
},
|
||||||
"components" : {
|
"components" : {
|
||||||
"schemas" : {
|
"schemas" : {
|
||||||
"TestDeleteResponse" : {
|
"String" : {
|
||||||
"properties" : { },
|
"type" : "string"
|
||||||
"type" : "object"
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Another get test",
|
"summary" : "Another get test",
|
||||||
"description" : "testing more",
|
"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" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor",
|
||||||
@ -56,6 +73,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type" : "object"
|
"type" : "object"
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Test post endpoint",
|
"summary" : "Test post endpoint",
|
||||||
"description" : "Post your tests here!",
|
"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" : {
|
"requestBody" : {
|
||||||
"description" : "A Test request",
|
"description" : "A Test request",
|
||||||
"content" : {
|
"content" : {
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Test put endpoint",
|
"summary" : "Test put endpoint",
|
||||||
"description" : "Put your tests here!",
|
"description" : "Put your tests here!",
|
||||||
|
"parameters" : [ ],
|
||||||
"requestBody" : {
|
"requestBody" : {
|
||||||
"description" : "A Test request",
|
"description" : "A Test request",
|
||||||
"content" : {
|
"content" : {
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Test put endpoint",
|
"summary" : "Test put endpoint",
|
||||||
"description" : "Put your tests here!",
|
"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" : {
|
"requestBody" : {
|
||||||
"description" : "A Test request",
|
"description" : "A Test request",
|
||||||
"content" : {
|
"content" : {
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Another get test",
|
"summary" : "Another get test",
|
||||||
"description" : "testing more",
|
"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" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor",
|
||||||
@ -56,6 +73,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type" : "object"
|
"type" : "object"
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -103,12 +103,6 @@
|
|||||||
"parameters" : [ {
|
"parameters" : [ {
|
||||||
"name" : "status",
|
"name" : "status",
|
||||||
"in" : "query",
|
"in" : "query",
|
||||||
"description" : "Status values that need to be considered for filter",
|
|
||||||
"required" : true,
|
|
||||||
"deprecated" : false,
|
|
||||||
"allowEmptyValue" : false,
|
|
||||||
"style" : "form",
|
|
||||||
"explode" : true,
|
|
||||||
"schema" : {
|
"schema" : {
|
||||||
"items" : {
|
"items" : {
|
||||||
"default" : "available",
|
"default" : "available",
|
||||||
@ -116,7 +110,12 @@
|
|||||||
"type" : "string"
|
"type" : "string"
|
||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
}
|
},
|
||||||
|
"description" : "Status values that need to be considered for filter",
|
||||||
|
"required" : true,
|
||||||
|
"deprecated" : false,
|
||||||
|
"style" : "form",
|
||||||
|
"explode" : true
|
||||||
} ],
|
} ],
|
||||||
"responses" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Another get test",
|
"summary" : "Another get test",
|
||||||
"description" : "testing more",
|
"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" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor",
|
||||||
@ -62,6 +79,10 @@
|
|||||||
"$ref" : "#/components/schemas/TestResponse"
|
"$ref" : "#/components/schemas/TestResponse"
|
||||||
},
|
},
|
||||||
"type" : "array"
|
"type" : "array"
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Another get test",
|
"summary" : "Another get test",
|
||||||
"description" : "testing more",
|
"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" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor",
|
||||||
@ -56,6 +73,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type" : "object"
|
"type" : "object"
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -28,6 +28,23 @@
|
|||||||
"tags" : [ ],
|
"tags" : [ ],
|
||||||
"summary" : "Another get test",
|
"summary" : "Another get test",
|
||||||
"description" : "testing more",
|
"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" : {
|
"responses" : {
|
||||||
"200" : {
|
"200" : {
|
||||||
"description" : "A Successful Endeavor",
|
"description" : "A Successful Endeavor",
|
||||||
@ -56,6 +73,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type" : "object"
|
"type" : "object"
|
||||||
|
},
|
||||||
|
"Int" : {
|
||||||
|
"format" : "int32",
|
||||||
|
"type" : "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securitySchemes" : { }
|
"securitySchemes" : { }
|
||||||
|
@ -31,6 +31,8 @@ import org.leafygreens.kompendium.Kompendium.notarizedPost
|
|||||||
import org.leafygreens.kompendium.Kompendium.notarizedPut
|
import org.leafygreens.kompendium.Kompendium.notarizedPut
|
||||||
import org.leafygreens.kompendium.Kompendium.openApiSpec
|
import org.leafygreens.kompendium.Kompendium.openApiSpec
|
||||||
import org.leafygreens.kompendium.annotations.KompendiumField
|
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.MethodInfo
|
||||||
import org.leafygreens.kompendium.models.meta.RequestInfo
|
import org.leafygreens.kompendium.models.meta.RequestInfo
|
||||||
import org.leafygreens.kompendium.models.meta.ResponseInfo
|
import org.leafygreens.kompendium.models.meta.ResponseInfo
|
||||||
@ -70,16 +72,16 @@ fun Application.mainModule() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
route("/single") {
|
route("/single") {
|
||||||
notarizedGet<ExampleRequest, ExampleResponse>(testSingleGetInfo) {
|
notarizedGet<Unit, ExampleResponse>(testSingleGetInfo) {
|
||||||
call.respondText("get single")
|
call.respondText("get single")
|
||||||
}
|
}
|
||||||
notarizedPost<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
|
notarizedPost<Unit, ExampleRequest, ExampleCreatedResponse>(testSinglePostInfo) {
|
||||||
call.respondText("test post")
|
call.respondText("test post")
|
||||||
}
|
}
|
||||||
notarizedPut<ExampleParams, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
|
notarizedPut<JustQuery, ExampleRequest, ExampleCreatedResponse>(testSinglePutInfo) {
|
||||||
call.respondText { "hey" }
|
call.respondText { "hey" }
|
||||||
}
|
}
|
||||||
notarizedDelete<Unit, DeleteResponse>(testSingleDeleteInfo) {
|
notarizedDelete<Unit, Unit>(testSingleDeleteInfo) {
|
||||||
call.respondText { "heya" }
|
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)
|
data class ExampleNested(val nesty: String)
|
||||||
|
|
||||||
object DeleteResponse
|
|
||||||
|
|
||||||
data class ExampleRequest(
|
data class ExampleRequest(
|
||||||
@KompendiumField(name = "field_name")
|
@KompendiumField(name = "field_name")
|
||||||
val fieldName: ExampleNested,
|
val fieldName: ExampleNested,
|
||||||
@ -150,7 +158,8 @@ object KompendiumTOC {
|
|||||||
description = "testing my deletes",
|
description = "testing my deletes",
|
||||||
responseInfo = ResponseInfo(
|
responseInfo = ResponseInfo(
|
||||||
status = KompendiumHttpCodes.NO_CONTENT,
|
status = KompendiumHttpCodes.NO_CONTENT,
|
||||||
description = "Signifies that your item was deleted succesfully"
|
description = "Signifies that your item was deleted successfully",
|
||||||
|
mediaTypes = emptyList()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user