org.http4k.contract.openapi.v3.model.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.openapi.v3
import org.http4k.contract.Tag
import org.http4k.contract.openapi.ApiInfo
import org.http4k.core.Uri
import org.http4k.lens.Meta
import org.http4k.lens.ParamMeta.ArrayParam
import org.http4k.lens.ParamMeta.FileParam
import org.http4k.util.JsonSchema
data class Api private constructor(
val info: ApiInfo,
val tags: List,
val servers: List,
val paths: Map>>,
val components: Components
) {
init {
require(servers.isNotEmpty())
{ "openAPI spec requires not-null and non-empty servers. See: https://swagger.io/specification/#openapi-object " }
}
constructor(
info: ApiInfo,
tags: List,
paths: Map>>,
components: Components,
servers: List
) : this(info, tags, servers.ifEmpty { listOf(ApiServer(Uri.of("/"))) }, paths, components)
val openapi = "3.0.0"
}
data class Components(
val schemas: NODE,
val securitySchemes: NODE
)
data class ApiServer(
val url: Uri,
val description: String? = null
)
sealed class ApiPath(
val summary: String,
val description: String?,
val tags: List,
val parameters: List>,
val responses: Map>,
val security: NODE,
val operationId: String,
val deprecated: Boolean
) {
open fun definitions() = listOfNotNull(
responses.flatMap { it.value.definitions() },
parameters.filterIsInstance>().flatMap { it.definitions() }
).flatten()
class NoBody(
summary: String,
description: String?,
tags: List,
parameters: List>,
responses: Map>,
security: NODE,
operationId: String,
deprecated: Boolean
) : ApiPath(summary, description, tags, parameters, responses, security, operationId, deprecated)
class WithBody(
summary: String,
description: String?,
tags: List,
parameters: List>,
val requestBody: RequestContents,
responses: Map>,
security: NODE,
operationId: String,
deprecated: Boolean
) : ApiPath(summary, description, tags, parameters, responses, security, operationId, deprecated) {
override fun definitions() = super.definitions() + requestBody.definitions().toList()
}
}
fun interface HasSchema {
fun definitions(): Iterable>
}
sealed class BodyContent {
data class NoSchema(val schema: NODE, val example: String? = null) : BodyContent()
class SchemaContent(private val jsonSchema: JsonSchema?, val example: NODE?) : BodyContent(),
HasSchema {
val schema = jsonSchema?.node
override fun definitions() = jsonSchema?.definitions ?: emptySet()
}
class OneOfSchemaContent(private val schemas: List) : BodyContent(), HasSchema {
data class OneOf(val oneOf: List)
val schema = OneOf(
schemas.filterIsInstance>().map { it.schema } +
schemas.filterIsInstance>().mapNotNull { it.schema }
)
override fun definitions() = schemas
.filterIsInstance>()
.flatMap { it.definitions() }
}
class FormContent(val schema: FormSchema) : BodyContent() {
class FormSchema(metas: List) {
val type = "object"
val properties = metas.associate {
val paramMeta = it.paramMeta
val listOfNotNull = listOfNotNull(
"type" to paramMeta.value,
paramMeta.takeIf { it == FileParam }?.let { "format" to "binary" },
it.description?.let { "description" to it },
if (paramMeta is ArrayParam) "items" to mapOf(
*listOfNotNull(
"type" to paramMeta.itemType().value,
paramMeta.itemType().takeIf { it == FileParam }
?.let { "format" to "binary" }).toTypedArray()
)
else null
)
it.name to listOfNotNull.toMap()
}
val required = metas.filter(Meta::required).map { it.name }
}
}
}
class RequestContents(val content: Map? = null) : HasSchema {
override fun definitions() = content?.values
?.filterIsInstance>()
?.flatMap { it.definitions() }
?: emptyList()
val required = content != null
}
class ResponseContents(val description: String?, val content: Map = emptyMap()) :
HasSchema {
override fun definitions() = content.values
.filterIsInstance>()
.flatMap { it.definitions() }.toSet()
}
sealed class RequestParameter(
val `in`: String,
val name: String,
val required: Boolean,
val description: String?
) {
class SchemaParameter(meta: Meta, private val jsonSchema: JsonSchema?) :
RequestParameter(meta.location, meta.name, meta.required, meta.description), HasSchema {
val schema: NODE? = jsonSchema?.node
override fun definitions() = jsonSchema?.definitions ?: emptySet()
}
class PrimitiveParameter(meta: Meta, val schema: NODE) :
RequestParameter(meta.location, meta.name, meta.required, meta.description)
}