org.http4k.contract.routeMeta.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http4k-contract Show documentation
Show all versions of http4k-contract Show documentation
http4k typesafe HTTP contracts and OpenApi support
package org.http4k.contract
import org.http4k.contract.security.Security
import org.http4k.core.ContentType
import org.http4k.core.HttpMessage
import org.http4k.core.Method.POST
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status
import org.http4k.core.with
import org.http4k.lens.BiDiBodyLens
import org.http4k.lens.BodyLens
import org.http4k.lens.Header
import org.http4k.lens.Lens
import org.http4k.util.Appendable
open class HttpMessageMeta(
val message: T,
val description: String,
val definitionId: String?,
val example: Any?,
val schemaPrefix: String? = null
)
class RequestMeta(request: Request, definitionId: String? = null, example: Any? = null, schemaPrefix: String? = null)
: HttpMessageMeta(request, "request", definitionId, example, schemaPrefix)
class ResponseMeta(description: String, response: Response, definitionId: String? = null, example: Any? = null, schemaPrefix: String? = null)
: HttpMessageMeta(response, description, definitionId, example, schemaPrefix)
class RouteMetaDsl internal constructor() {
var summary: String = ""
var description: String? = null
val tags = Appendable()
val produces = Appendable()
val consumes = Appendable()
internal val requests = Appendable>()
internal val responses = Appendable>()
val headers = Appendable>()
val queries = Appendable>()
val cookies = Appendable>()
internal var requestBody: BodyLens<*>? = null
var operationId: String? = null
var security: Security? = null
var preFlightExtraction: PreFlightExtraction? = null
internal var deprecated: Boolean = false
/**
* Add possible responses to this Route.
*/
@JvmName("returningResponse")
fun returning(vararg descriptionToResponse: Pair) =
descriptionToResponse.forEach { (description, status) -> returning(ResponseMeta(description, status)) }
/**
* Add possible response metadata to this Route. A route supports multiple possible responses.
*/
@JvmName("returningResponseMeta")
fun returning(vararg responseMetas: HttpMessageMeta) {
responseMetas.forEach { responses += it }
responseMetas.forEach {
produces += Header.CONTENT_TYPE(it.message)?.let { listOf(it) } ?: emptyList()
}
}
/**
* Add a possible response description/reason and status to this Route
*/
@JvmName("returningStatus")
fun returning(vararg statusesToDescriptions: Pair) =
statusesToDescriptions.forEach { (status, d) -> returning(d to Response(status)) }
/**
* Add possible response statuses to this Route with no example.
*/
@JvmName("returningStatus")
fun returning(vararg statuses: Status) = statuses.forEach { returning(ResponseMeta("", Response(it))) }
/**
* Add an example response (using a Lens and a value) to this Route. It is also possible to pass in the definitionId
* for this response body which will override the naturally generated one.
*/
@JvmName("returningStatus")
fun returning(status: Status, body: Pair, T>,
description: String? = null,
definitionId: String? = null,
schemaPrefix: String? = null
) {
returning(ResponseMeta(description
?: status.description, Response(status).with(body.first of body.second), definitionId, body.second, schemaPrefix))
}
/**
* Add an example request (using a Lens and a value) to this Route. It is also possible to pass in the definitionId
* for this request body which will override the naturally generated one.
*/
fun receiving(body: Pair, T>,
definitionId: String? = null,
schemaPrefix: String? = null
) {
requestBody = body.first
receiving(RequestMeta(Request(POST, "").with(body.first of body.second), definitionId, body.second, schemaPrefix))
}
/**
* Add request metadata to this Route. A route only supports a single possible request.
*/
fun receiving(requestMeta: HttpMessageMeta) {
requests += requestMeta
consumes += Header.CONTENT_TYPE(requestMeta.message)?.let { listOf(it) } ?: emptyList()
}
/**
* Set the input body type for this request WITHOUT an example. Hence the content-type will be registered but no
* example schema will be generated.
*/
fun receiving(bodyLens: BiDiBodyLens) {
requestBody = bodyLens
receiving(RequestMeta(Request(POST, "").with(Header.CONTENT_TYPE of bodyLens.contentType)))
}
fun markAsDeprecated() {
deprecated = true
}
}
fun routeMetaDsl(fn: RouteMetaDsl.() -> Unit = {}) = RouteMetaDsl().apply(fn).run {
RouteMeta(
summary, description, tags.all.toSet(), requestBody, produces.all.toSet(), consumes.all.toSet(), queries.all + headers.all + cookies.all, requests.all, responses.all, preFlightExtraction, security, operationId, deprecated
)
}
data class RouteMeta(val summary: String = "",
val description: String? = null,
val tags: Set = emptySet(),
val body: BodyLens<*>? = null,
val produces: Set = emptySet(),
val consumes: Set = emptySet(),
val requestParams: List> = emptyList(),
val requests: List> = emptyList(),
val responses: List> = emptyList(),
val preFlightExtraction: PreFlightExtraction? = null,
val security: Security? = null,
val operationId: String? = null,
val deprecated: Boolean = false)