feat: v2-alpha (#112)
There are still some bugs, still some outstanding features, but I don't want to hold this back any longer, that way I can keep the future PRs much more focused
This commit is contained in:
55
kompendium-oas/Module.md
Normal file
55
kompendium-oas/Module.md
Normal file
@ -0,0 +1,55 @@
|
||||
# Module kompendium-oas
|
||||
|
||||
## Open Api Specification
|
||||
|
||||
This module contains the models that represent the Open Api Specification 3.0 (OAS).
|
||||
|
||||
It is a purely domain-based module, with no logic whatsoever.
|
||||
|
||||
The specification can be found [here](https://swagger.io/specification).
|
||||
|
||||
# Package io.bkbn.kompendium.oas
|
||||
|
||||
This is the root package that contains the top level spec that is ultimately serialized into the specification JSON
|
||||
payload.
|
||||
|
||||
# Package io.bkbn.kompendium.oas.common
|
||||
|
||||
Here we house data models that will be used across the module.
|
||||
|
||||
# Package io.bkbn.kompendium.oas.component
|
||||
|
||||
This package correlates to the OAS Component layer, which at the moment is relatively bare bones. It will just contain a
|
||||
reference to any security schemas, as adding objects here as components severely limits future ability to add cool
|
||||
features such as route level object validations. Got issues with that, bring it up with the Open API Team :)
|
||||
|
||||
# Package io.bkbn.kompendium.oas.info
|
||||
|
||||
This package houses the data models for information metadata such as contact and licensing info
|
||||
|
||||
# Package io.bkbn.kompendium.oas.path
|
||||
|
||||
Now we're getting to the good stuff. This is where the details on each path level operation will live. Your `gets`,
|
||||
your `puts`, so on and so forth.
|
||||
|
||||
# Package io.bkbn.kompendium.oas.payload
|
||||
|
||||
This is another good one, this is where the actual payload types live. Request and response body specifications,
|
||||
parameter details, collection support. That all lives here.
|
||||
|
||||
# Package io.bkbn.kompendium.oas.schema
|
||||
|
||||
A bit confusingly, in the OAS, there is a distinction between a payload and a schema. You can think of payloads as
|
||||
containing schemas. So here we dive into the true object level definitions that we want to map out. Models for
|
||||
supporting collections, dictionaries, polymorphic classes, enums, along with your standard library classes all live
|
||||
here.
|
||||
|
||||
# Package io.bkbn.kompendium.oas.security
|
||||
|
||||
Separated from the core schema models are the models that represent security schemas. Despite being referred to as
|
||||
schemas, and despite living as part of the component data structure, these models are drastically different from your
|
||||
core data model schemas, and thus earn their own package
|
||||
|
||||
# Package io.bkbn.kompendium.oas.server
|
||||
|
||||
Here we detail any server information that you wish to attach to your specification
|
3
kompendium-oas/build.gradle.kts
Normal file
3
kompendium-oas/build.gradle.kts
Normal file
@ -0,0 +1,3 @@
|
||||
plugins {
|
||||
id("io.bkbn.sourdough.library")
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package io.bkbn.kompendium.oas
|
||||
|
||||
import io.bkbn.kompendium.oas.common.ExternalDocumentation
|
||||
import io.bkbn.kompendium.oas.common.Tag
|
||||
import io.bkbn.kompendium.oas.component.Components
|
||||
import io.bkbn.kompendium.oas.info.Info
|
||||
import io.bkbn.kompendium.oas.path.Path
|
||||
import io.bkbn.kompendium.oas.server.Server
|
||||
|
||||
data class OpenApiSpec(
|
||||
val openapi: String = "3.0.3",
|
||||
val info: Info,
|
||||
val servers: MutableList<Server> = mutableListOf(),
|
||||
val paths: MutableMap<String, Path> = mutableMapOf(),
|
||||
val components: Components = Components(),
|
||||
val security: MutableList<Map<String, List<String>>> = mutableListOf(),
|
||||
val tags: MutableList<Tag> = mutableListOf(),
|
||||
val externalDocs: ExternalDocumentation? = null
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package io.bkbn.kompendium.oas.common
|
||||
|
||||
import java.net.URI
|
||||
|
||||
data class ExternalDocumentation(
|
||||
val url: URI,
|
||||
val description: String?
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package io.bkbn.kompendium.oas.common
|
||||
|
||||
data class Tag(
|
||||
val name: String,
|
||||
val description: String? = null,
|
||||
val externalDocs: ExternalDocumentation? = null
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package io.bkbn.kompendium.oas.component
|
||||
|
||||
import io.bkbn.kompendium.oas.security.SecuritySchema
|
||||
|
||||
data class Components(
|
||||
val securitySchemes: MutableMap<String, SecuritySchema> = mutableMapOf()
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package io.bkbn.kompendium.oas.info
|
||||
|
||||
import java.net.URI
|
||||
|
||||
data class Contact(
|
||||
var name: String,
|
||||
var url: URI? = null,
|
||||
var email: String? = null // TODO Enforce email?
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package io.bkbn.kompendium.oas.info
|
||||
|
||||
import java.net.URI
|
||||
|
||||
data class Info(
|
||||
var title: String? = null,
|
||||
var version: String? = null,
|
||||
var description: String? = null,
|
||||
var termsOfService: URI? = null,
|
||||
var contact: Contact? = null,
|
||||
var license: License? = null
|
||||
)
|
@ -0,0 +1,8 @@
|
||||
package io.bkbn.kompendium.oas.info
|
||||
|
||||
import java.net.URI
|
||||
|
||||
data class License(
|
||||
var name: String,
|
||||
var url: URI? = null
|
||||
)
|
@ -0,0 +1,17 @@
|
||||
package io.bkbn.kompendium.oas.path
|
||||
|
||||
import io.bkbn.kompendium.oas.payload.Parameter
|
||||
import io.bkbn.kompendium.oas.server.Server
|
||||
|
||||
data class Path(
|
||||
var get: PathOperation? = null,
|
||||
var put: PathOperation? = null,
|
||||
var post: PathOperation? = null,
|
||||
var delete: PathOperation? = null,
|
||||
var options: PathOperation? = null,
|
||||
var head: PathOperation? = null,
|
||||
var patch: PathOperation? = null,
|
||||
var trace: PathOperation? = null,
|
||||
var servers: List<Server>? = null,
|
||||
var parameters: List<Parameter>? = null
|
||||
)
|
@ -0,0 +1,25 @@
|
||||
package io.bkbn.kompendium.oas.path
|
||||
|
||||
import io.bkbn.kompendium.oas.common.ExternalDocumentation
|
||||
import io.bkbn.kompendium.oas.payload.Parameter
|
||||
import io.bkbn.kompendium.oas.payload.Payload
|
||||
import io.bkbn.kompendium.oas.payload.Request
|
||||
import io.bkbn.kompendium.oas.payload.Response
|
||||
import io.bkbn.kompendium.oas.server.Server
|
||||
|
||||
data class PathOperation(
|
||||
var tags: Set<String> = emptySet(),
|
||||
var summary: String? = null,
|
||||
var description: String? = null,
|
||||
var externalDocs: ExternalDocumentation? = null,
|
||||
var operationId: String? = null,
|
||||
var parameters: List<Parameter>? = null,
|
||||
var requestBody: Request<*>? = null,
|
||||
// TODO How to enforce `default` requirement 🧐
|
||||
var responses: Map<Int, Response<*>>? = null,
|
||||
var callbacks: Map<String, Payload>? = null, // todo what is this?
|
||||
var deprecated: Boolean = false,
|
||||
var security: List<Map<String, List<String>>>? = null,
|
||||
var servers: List<Server>? = null,
|
||||
var `x-codegen-request-body-name`: String? = null
|
||||
)
|
@ -0,0 +1,5 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||
|
||||
data class AnyOfPayload(val anyOf: List<ComponentSchema>) : Payload
|
@ -0,0 +1,10 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||
|
||||
data class MediaType<T>(
|
||||
val schema: ComponentSchema,
|
||||
val examples: Map<String, Example<T>>? = null
|
||||
) {
|
||||
data class Example<T>(val value: T)
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
import io.bkbn.kompendium.oas.schema.ComponentSchema
|
||||
|
||||
data class Parameter(
|
||||
val name: String,
|
||||
val `in`: String, // TODO Enum? "query", "header", "path" or "cookie"
|
||||
val schema: ComponentSchema,
|
||||
val description: String? = null,
|
||||
val required: Boolean = true,
|
||||
val deprecated: Boolean = false,
|
||||
val allowEmptyValue: Boolean? = null,
|
||||
val style: String? = null,
|
||||
val explode: Boolean? = null
|
||||
)
|
@ -0,0 +1,3 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
sealed interface Payload
|
@ -0,0 +1,7 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
data class Request<T>(
|
||||
val description: String?,
|
||||
val content: Map<String, MediaType<T>>,
|
||||
val required: Boolean = false
|
||||
) : Payload
|
@ -0,0 +1,8 @@
|
||||
package io.bkbn.kompendium.oas.payload
|
||||
|
||||
data class Response<T>(
|
||||
val description: String? = null,
|
||||
val headers: Map<String, Payload>? = null,
|
||||
val content: Map<String, MediaType<T>>? = null,
|
||||
val links: Map<String, Payload>? = null
|
||||
) : Payload
|
@ -0,0 +1,3 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class AnyOfSchema(val anyOf: List<ComponentSchema>, override val description: String? = null) : ComponentSchema
|
@ -0,0 +1,14 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class ArraySchema(
|
||||
val items: ComponentSchema,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null,
|
||||
// constraints
|
||||
val minItems: Int? = null,
|
||||
val maxItems: Int? = null,
|
||||
val uniqueItems: Boolean? = null
|
||||
) : TypedSchema {
|
||||
override val type: String = "array"
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
sealed interface ComponentSchema {
|
||||
val description: String?
|
||||
get() = null
|
||||
|
||||
val default: Any?
|
||||
get() = null
|
||||
|
||||
fun addDefault(default: Any?): ComponentSchema = when (this) {
|
||||
is AnyOfSchema -> error("Cannot add default to anyOf reference") // todo is this true though?
|
||||
is ArraySchema -> this.copy(default = default)
|
||||
is DictionarySchema -> this.copy(default = default)
|
||||
is EnumSchema -> this.copy(default = default)
|
||||
is FormattedSchema -> this.copy(default = default)
|
||||
is ObjectSchema -> this.copy(default = default)
|
||||
is SimpleSchema -> this.copy(default = default)
|
||||
else -> error("Compiler bug??")
|
||||
}
|
||||
|
||||
fun setDescription(description: String): ComponentSchema = when (this) {
|
||||
is AnyOfSchema -> this.copy(description = description)
|
||||
is ArraySchema -> this.copy(description = description)
|
||||
is DictionarySchema -> this.copy(description = description)
|
||||
is EnumSchema -> this.copy(description = description)
|
||||
is FormattedSchema -> this.copy(description = description)
|
||||
is ObjectSchema -> this.copy(description = description)
|
||||
is SimpleSchema -> this.copy(description = description)
|
||||
else -> error("Compiler bug??")
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class DictionarySchema(
|
||||
val additionalProperties: ComponentSchema,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null
|
||||
) : TypedSchema {
|
||||
override val type: String = "object"
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class EnumSchema(
|
||||
val `enum`: Set<String>,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null
|
||||
) : TypedSchema {
|
||||
override val type: String = "string"
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class FormattedSchema(
|
||||
val format: String,
|
||||
override val type: String,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null,
|
||||
// Constraints
|
||||
val minimum: Number? = null,
|
||||
val maximum: Number? = null,
|
||||
val exclusiveMinimum: Boolean? = null,
|
||||
val exclusiveMaximum: Boolean? = null,
|
||||
val multipleOf: Number? = null,
|
||||
) : TypedSchema
|
@ -0,0 +1,12 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class FreeFormSchema(
|
||||
override val nullable: Boolean? = null,
|
||||
// constraints
|
||||
val minProperties: Int? = null,
|
||||
val maxProperties: Int? = null
|
||||
) : TypedSchema {
|
||||
val additionalProperties: Boolean = true
|
||||
override val type: String = "object"
|
||||
override val default: Any? = null
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class ObjectSchema(
|
||||
val properties: Map<String, ComponentSchema>,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null,
|
||||
// constraints
|
||||
val required: List<String>? = null
|
||||
) : TypedSchema {
|
||||
override val type = "object"
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
data class SimpleSchema(
|
||||
override val type: String,
|
||||
override val default: Any? = null,
|
||||
override val description: String? = null,
|
||||
override val nullable: Boolean? = null,
|
||||
// Constraints
|
||||
val minLength: Int? = null,
|
||||
val maxLength: Int? = null,
|
||||
val pattern: String? = null,
|
||||
val format: String? = null
|
||||
) : TypedSchema
|
@ -0,0 +1,7 @@
|
||||
package io.bkbn.kompendium.oas.schema
|
||||
|
||||
sealed interface TypedSchema : ComponentSchema {
|
||||
val type: String
|
||||
val nullable: Boolean?
|
||||
override val default: Any?
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.bkbn.kompendium.oas.security
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
// TODO... is there even an official ktor api auth mechanism??
|
||||
|
||||
@Suppress("UnusedPrivateMember")
|
||||
class ApiKeyAuth(val `in`: ApiKeyLocation, name: String) : SecuritySchema {
|
||||
val type: String = "apiKey"
|
||||
|
||||
enum class ApiKeyLocation {
|
||||
HEADER,
|
||||
QUERY,
|
||||
COOKIE;
|
||||
|
||||
override fun toString(): String = name.lowercase(Locale.getDefault())
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package io.bkbn.kompendium.oas.security
|
||||
|
||||
class BasicAuth : SecuritySchema {
|
||||
val type: String = "http"
|
||||
val scheme: String = "basic"
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package io.bkbn.kompendium.oas.security
|
||||
|
||||
data class BearerAuth(val bearerFormat: String? = null): SecuritySchema {
|
||||
val type: String = "http"
|
||||
val scheme: String = "bearer"
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package io.bkbn.kompendium.oas.security
|
||||
|
||||
data class OAuth(val description: String? = null, val flows: Flows) : SecuritySchema {
|
||||
val type: String = "oauth2"
|
||||
|
||||
data class Flows(
|
||||
val implicit: Implicit? = null,
|
||||
val authorizationCode: AuthorizationCode? = null,
|
||||
val password: Password? = null,
|
||||
val clientCredentials: ClientCredential? = null,
|
||||
) {
|
||||
|
||||
sealed interface Flow {
|
||||
val authorizationUrl: String?
|
||||
get() = null
|
||||
val tokenUrl: String?
|
||||
get() = null
|
||||
val refreshUrl: String?
|
||||
get() = null
|
||||
val scopes: Map<String, String>
|
||||
get() = emptyMap()
|
||||
}
|
||||
|
||||
data class Implicit(
|
||||
override val authorizationUrl: String,
|
||||
override val refreshUrl: String? = null,
|
||||
override val scopes: Map<String, String> = emptyMap()
|
||||
) : Flow
|
||||
|
||||
data class AuthorizationCode(
|
||||
override val authorizationUrl: String,
|
||||
override val tokenUrl: String? = null,
|
||||
override val refreshUrl: String? = null,
|
||||
override val scopes: Map<String, String> = emptyMap()
|
||||
) : Flow
|
||||
|
||||
data class Password(
|
||||
override val tokenUrl: String? = null,
|
||||
override val refreshUrl: String? = null,
|
||||
override val scopes: Map<String, String> = emptyMap()
|
||||
) : Flow
|
||||
|
||||
data class ClientCredential(
|
||||
override val tokenUrl: String? = null,
|
||||
override val refreshUrl: String? = null,
|
||||
override val scopes: Map<String, String> = emptyMap()
|
||||
) : Flow
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package io.bkbn.kompendium.oas.security
|
||||
|
||||
sealed interface SecuritySchema
|
@ -0,0 +1,9 @@
|
||||
package io.bkbn.kompendium.oas.server
|
||||
|
||||
import java.net.URI
|
||||
|
||||
data class Server(
|
||||
val url: URI,
|
||||
val description: String? = null,
|
||||
var variables: Map<String, ServerVariable>? = null
|
||||
)
|
@ -0,0 +1,7 @@
|
||||
package io.bkbn.kompendium.oas.server
|
||||
|
||||
data class ServerVariable(
|
||||
val `enum`: Set<String>, // todo enforce not empty
|
||||
val default: String,
|
||||
val description: String?
|
||||
)
|
Reference in New Issue
Block a user