diff --git a/HowToRelease.md b/HowToRelease.md
new file mode 100644
index 00000000..afa95656
--- /dev/null
+++ b/HowToRelease.md
@@ -0,0 +1,9 @@
+# How to release
+
+https://vanniktech.github.io/gradle-maven-publish-plugin/central/
+
+1. Credentials should be configured in a gradle.properties file (in user home)
+
+2. `./gradlew publishAllPublicationsToMavenCentral --no-configuration-cache`
+
+3. `./gradlew closeAndReleaseRepository`
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 32b8f281..0bca512d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ import io.gitlab.arturbosch.detekt.Detekt
object Meta {
const val groupId = "io.github.smiley4"
const val artifactId = "ktor-swagger-ui"
- const val version = "2.5.0"
+ const val version = "2.6.0"
const val name = "Ktor Swagger-UI"
const val description = "Ktor plugin to document routes and provide Swagger UI"
const val licenseName = "The Apache License, Version 2.0"
@@ -68,7 +68,7 @@ dependencies {
val versionMockk = "1.12.7"
testImplementation("io.mockk:mockk:$versionMockk")
- val versionKotest = "5.4.2"
+ val versionKotest = "5.7.2"
testImplementation("io.kotest:kotest-runner-junit5:$versionKotest")
testImplementation("io.kotest:kotest-assertions-core:$versionKotest")
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt
deleted file mode 100644
index d5f4fcda..00000000
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-package io.github.smiley4.ktorswaggerui
-
-import io.github.smiley4.ktorswaggerui.dsl.SwaggerUIDsl
-import io.github.smiley4.ktorswaggerui.dsl.SwaggerUiSort
-import io.ktor.http.ContentType
-import io.ktor.http.HttpStatusCode
-import io.ktor.http.content.OutgoingContent
-import io.ktor.http.withCharset
-import io.ktor.server.application.ApplicationCall
-import io.ktor.server.response.respond
-import io.ktor.server.response.respondText
-import java.net.URL
-
-class SwaggerController(
- private val swaggerWebjarVersion: String,
- private val apiSpecUrl: String,
- private val jsonSpecProvider: () -> String,
- private val swaggerUiConfig: SwaggerUIDsl
-) {
-
- suspend fun serveOpenApiSpec(call: ApplicationCall) {
- call.respondText(ContentType.Application.Json, HttpStatusCode.OK, jsonSpecProvider)
- }
-
- suspend fun serverSwaggerUI(call: ApplicationCall) {
- when (val filename = call.parameters["filename"]!!) {
- "swagger-initializer.js" -> serveSwaggerInitializer(call)
- else -> serveStaticResource(filename, call)
- }
- }
-
- private suspend fun serveSwaggerInitializer(call: ApplicationCall) {
- val propValidatorUrl = swaggerUiConfig.getSpecValidatorUrl()?.let { "validatorUrl: \"$it\"" } ?: "validatorUrl: false"
- val propDisplayOperationId = "displayOperationId: ${swaggerUiConfig.displayOperationId}"
- val propFilter = "filter: ${swaggerUiConfig.showTagFilterInput}"
- val propSort = "operationsSorter: " + if (swaggerUiConfig.sort == SwaggerUiSort.NONE) "undefined" else
- "\"${swaggerUiConfig.sort.value}\""
- val propSyntaxHighlight = "syntaxHighlight: { theme: \"${swaggerUiConfig.syntaxHighlight.value}\" }"
- // see https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md for reference
- val content = """
- window.onload = function() {
- //
- window.ui = SwaggerUIBundle({
- url: "$apiSpecUrl",
- dom_id: '#swagger-ui',
- deepLinking: true,
- presets: [
- SwaggerUIBundle.presets.apis,
- SwaggerUIStandalonePreset
- ],
- plugins: [
- SwaggerUIBundle.plugins.DownloadUrl
- ],
- layout: "StandaloneLayout",
- $propValidatorUrl,
- $propDisplayOperationId,
- $propFilter,
- $propSort,
- $propSyntaxHighlight
- });
- //
- };
- """.trimIndent()
- call.respondText(ContentType.Application.JavaScript, HttpStatusCode.OK) { content }
- }
-
-
- private suspend fun serveStaticResource(filename: String, call: ApplicationCall) {
- val resource = this::class.java.getResource("/META-INF/resources/webjars/swagger-ui/$swaggerWebjarVersion/$filename")
- if (resource == null) {
- call.respond(HttpStatusCode.NotFound, "$filename could not be found")
- } else {
- call.respond(ResourceContent(resource))
- }
- }
-
-}
-
-
-private class ResourceContent(val resource: URL) : OutgoingContent.ByteArrayContent() {
- private val bytes by lazy { resource.readBytes() }
-
- override val contentType: ContentType? by lazy {
- val extension = resource.file.substring(resource.file.lastIndexOf('.') + 1)
- contentTypes[extension] ?: ContentType.Text.Html
- }
-
- override val contentLength: Long? by lazy {
- bytes.size.toLong()
- }
-
- override fun bytes(): ByteArray = bytes
-
- override fun toString() = "ResourceContent \"$resource\""
-}
-
-
-private val contentTypes = mapOf(
- "html" to ContentType.Text.Html,
- "css" to ContentType.Text.CSS,
- "js" to ContentType.Application.JavaScript,
- "json" to ContentType.Application.Json.withCharset(Charsets.UTF_8),
- "png" to ContentType.Image.PNG
-)
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt
index f019555b..372f874c 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt
@@ -1,20 +1,51 @@
package io.github.smiley4.ktorswaggerui
import com.fasterxml.jackson.databind.ObjectMapper
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.*
-import io.github.smiley4.ktorswaggerui.spec.route.RouteCollector
-import io.github.smiley4.ktorswaggerui.spec.route.RouteDocumentationMerger
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
-import io.ktor.server.application.*
-import io.ktor.server.application.hooks.*
-import io.ktor.server.routing.*
-import io.ktor.server.webjars.*
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
+import io.github.smiley4.ktorswaggerui.routing.ForwardRouteController
+import io.github.smiley4.ktorswaggerui.routing.SwaggerController
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ComponentsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ContactBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ContentBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExampleBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExternalDocumentationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.HeaderBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.InfoBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.LicenseBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OAuthFlowsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OpenApiBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationTagsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ParameterBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.PathBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.PathsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.RequestBodyBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponseBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponsesBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.SecurityRequirementsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.SecuritySchemesBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ServerBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.TagBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.TagExternalDocumentationBuilder
+import io.github.smiley4.ktorswaggerui.builder.route.RouteCollector
+import io.github.smiley4.ktorswaggerui.builder.route.RouteDocumentationMerger
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
+import io.ktor.server.application.Application
+import io.ktor.server.application.ApplicationStarted
+import io.ktor.server.application.createApplicationPlugin
+import io.ktor.server.application.hooks.MonitoringEvent
+import io.ktor.server.application.install
+import io.ktor.server.application.plugin
+import io.ktor.server.application.pluginOrNull
+import io.ktor.server.routing.Routing
+import io.ktor.server.webjars.Webjars
import io.swagger.v3.core.util.Json
import mu.KotlinLogging
@@ -25,56 +56,96 @@ internal const val SWAGGER_UI_WEBJARS_VERSION = "4.15.0"
private val logger = KotlinLogging.logger {}
-val SwaggerUI = createApplicationPlugin(name = "SwaggerUI", createConfiguration = ::SwaggerUIPluginConfig) {
- var apiSpecJson = "{}"
+val SwaggerUI = createApplicationPlugin(name = "SwaggerUI", createConfiguration = ::PluginConfigDsl) {
+
+ val config = pluginConfig.build(PluginConfigData.DEFAULT)
+
on(MonitoringEvent(ApplicationStarted)) { application ->
+
if (application.pluginOrNull(Webjars) == null) {
application.install(Webjars)
}
+
+ val apiSpecsJson = mutableMapOf()
try {
- val routes = routes(application, pluginConfig)
- val schemaContext = schemaContext(pluginConfig, routes)
- val exampleContext = exampleContext(pluginConfig, routes)
- val openApi = builder(pluginConfig, schemaContext, exampleContext).build(routes)
- apiSpecJson = Json.pretty(openApi)
+ val routes = routes(application, config)
+ apiSpecsJson.putAll(buildOpenApiSpecs(config, routes))
} catch (e: Exception) {
- logger.error("Error during openapi-generation", e)
+ logger.error("Error during application startup in swagger-ui-plugin", e)
+ }
+
+ apiSpecsJson.forEach { (specId, json) ->
+ val specConfig = config.specConfigs[specId] ?: config
+ SwaggerController(
+ applicationConfig!!,
+ specConfig,
+ SWAGGER_UI_WEBJARS_VERSION,
+ if (apiSpecsJson.size > 1) specId else null,
+ json
+ ).setup(application)
+ }
+
+ if (apiSpecsJson.size == 1 && config.swaggerUI.forwardRoot) {
+ ForwardRouteController(applicationConfig!!, config).setup(application)
}
+
}
- SwaggerRouting(
- pluginConfig.getSwaggerUI(),
- application.environment.config,
- SWAGGER_UI_WEBJARS_VERSION,
- ) { apiSpecJson }.setup(application)
}
-private fun routes(application: Application, pluginConfig: SwaggerUIPluginConfig): List {
+private fun buildOpenApiSpecs(config: PluginConfigData, routes: List): Map {
+ val routesBySpec = buildMap> {
+ routes.forEach { route ->
+ val specName = route.documentation.specId ?: config.specAssigner(route.path, route.documentation.tags)
+ computeIfAbsent(specName) { mutableListOf() }.add(route)
+ }
+ }
+ return buildMap {
+ routesBySpec.forEach { (specName, routes) ->
+ val specConfig = config.specConfigs[specName] ?: config
+ this[specName] = buildOpenApiSpec(specConfig, routes)
+ }
+ }
+}
+
+private fun buildOpenApiSpec(pluginConfig: PluginConfigData, routes: List): String {
+ return try {
+ val schemaContext = schemaContext(pluginConfig, routes)
+ val exampleContext = exampleContext(pluginConfig, routes)
+ val openApi = builder(pluginConfig, schemaContext, exampleContext).build(routes)
+ Json.pretty(openApi)
+ } catch (e: Exception) {
+ logger.error("Error during openapi-generation", e)
+ "{}"
+ }
+}
+
+private fun routes(application: Application, config: PluginConfigData): List {
return RouteCollector(RouteDocumentationMerger())
- .collectRoutes({ application.plugin(Routing) }, pluginConfig)
+ .collectRoutes({ application.plugin(Routing) }, config)
.toList()
}
-private fun schemaContext(pluginConfig: SwaggerUIPluginConfig, routes: List): SchemaContext {
+private fun schemaContext(config: PluginConfigData, routes: List): SchemaContext {
return SchemaContextBuilder(
- config = pluginConfig,
+ config = config,
schemaBuilder = SchemaBuilder(
- definitionsField = pluginConfig.encodingConfig.schemaDefinitionsField,
- schemaEncoder = pluginConfig.encodingConfig.getSchemaEncoder(),
+ definitionsField = config.encoding.schemaDefsField,
+ schemaEncoder = config.encoding.schemaEncoder,
ObjectMapper(),
TypeOverwrites.get()
),
).build(routes.toList())
}
-private fun exampleContext(pluginConfig: SwaggerUIPluginConfig, routes: List): ExampleContext {
+private fun exampleContext(config: PluginConfigData, routes: List): ExampleContext {
return ExampleContextBuilder(
exampleBuilder = ExampleBuilder(
- config = pluginConfig
+ config = config
)
).build(routes.toList())
}
-private fun builder(config: SwaggerUIPluginConfig, schemaContext: SchemaContext, exampleContext: ExampleContext): OpenApiBuilder {
+private fun builder(config: PluginConfigData, schemaContext: SchemaContext, exampleContext: ExampleContext): OpenApiBuilder {
return OpenApiBuilder(
config = config,
schemaContext = schemaContext,
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt
deleted file mode 100644
index a3ed89bd..00000000
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package io.github.smiley4.ktorswaggerui
-
-import io.github.smiley4.ktorswaggerui.dsl.SwaggerUIDsl
-import io.ktor.server.application.Application
-import io.ktor.server.application.call
-import io.ktor.server.auth.authenticate
-import io.ktor.server.config.ApplicationConfig
-import io.ktor.server.response.respondRedirect
-import io.ktor.server.routing.Route
-import io.ktor.server.routing.get
-import io.ktor.server.routing.route
-import io.ktor.server.routing.routing
-import mu.KotlinLogging
-
-/**
- * Registers and handles routes required for the swagger-ui
- */
-class SwaggerRouting(
- private val swaggerUiConfig: SwaggerUIDsl,
- appConfig: ApplicationConfig,
- swaggerWebjarVersion: String,
- jsonSpecProvider: () -> String
-) {
-
- private val logger = KotlinLogging.logger {}
-
- private val controller = SwaggerController(
- swaggerWebjarVersion = swaggerWebjarVersion,
- apiSpecUrl = getApiSpecUrl(appConfig),
- jsonSpecProvider = jsonSpecProvider,
- swaggerUiConfig = swaggerUiConfig
- )
-
- private fun getApiSpecUrl(appConfig: ApplicationConfig): String {
- val rootPath = appConfig.propertyOrNull("ktor.deployment.rootPath")?.getString()?.let { "/${dropSlashes(it)}" } ?: ""
- return "$rootPath${swaggerUiConfig.rootHostPath}/${dropSlashes(swaggerUiConfig.swaggerUrl)}/api.json"
- }
-
- private fun dropSlashes(str: String): String {
- var value = str
- value = if (value.startsWith("/")) value.substring(1) else value
- value = if (value.endsWith("/")) value.substring(0, value.length - 1) else value
- return value
- }
-
- /**
- * registers the required routes
- */
- fun setup(app: Application) {
- val swaggerUrl = swaggerUiConfig.swaggerUrl
- val forwardRoot = swaggerUiConfig.forwardRoot
- val authentication = swaggerUiConfig.authentication
- logger.info("Registering routes for swagger-ui: $swaggerUrl (forwardRoot=$forwardRoot)")
- app.routing {
- if (forwardRoot) {
- get("/") {
- call.respondRedirect("${swaggerUiConfig.rootHostPath}/${dropSlashes(swaggerUrl)}/index.html")
- }
- }
- if (authentication == null) {
- setupSwaggerRoutes()
- } else {
- authenticate(authentication) {
- setupSwaggerRoutes()
- }
- }
- }
- }
-
- private fun Route.setupSwaggerRoutes() {
- val swaggerUrl = swaggerUiConfig.swaggerUrl
- route(swaggerUrl) {
- get {
- call.respondRedirect("${swaggerUiConfig.rootHostPath}/${dropSlashes(swaggerUrl)}/index.html")
- }
- get("api.json") {
- controller.serveOpenApiSpec(call)
- }
- get("{filename}") {
- controller.serverSwaggerUI(call)
- }
- }
- }
-
-}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt
deleted file mode 100644
index 9059928b..00000000
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerUIPluginConfig.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-package io.github.smiley4.ktorswaggerui
-
-import io.github.smiley4.ktorswaggerui.dsl.*
-import io.ktor.http.*
-import io.ktor.server.routing.*
-import kotlin.reflect.KClass
-
-/**
- * Main-Configuration of the "SwaggerUI"-Plugin
- */
-@OpenApiDslMarker
-class SwaggerUIPluginConfig {
-
- /**
- * Default response to automatically add to each protected route for the "Unauthorized"-Response-Code.
- * Generated response can be overwritten with custom response.
- */
- fun defaultUnauthorizedResponse(block: OpenApiResponse.() -> Unit) {
- defaultUnauthorizedResponse = OpenApiResponse(HttpStatusCode.Unauthorized.value.toString()).apply(block)
- }
-
- private var defaultUnauthorizedResponse: OpenApiResponse? = null
-
- fun getDefaultUnauthorizedResponse() = defaultUnauthorizedResponse
-
-
- /**
- * The name of the security scheme to use for the protected paths
- */
- var defaultSecuritySchemeName: String? = null
-
-
- /**
- * The names of the security schemes available for use for the protected paths
- */
- var defaultSecuritySchemeNames: Collection? = null
-
-
- /**
- * Automatically add tags to the route with the given url.
- * The returned (non-null) tags will be added to the tags specified in the route-specific documentation.
- */
- fun generateTags(generator: TagGenerator) {
- tagGenerator = generator
- }
-
- private var tagGenerator: TagGenerator = { emptyList() }
-
- fun getTagGenerator() = tagGenerator
-
-
- /**
- * Filter to apply to all routes. Return 'false' for routes to not include them in the OpenApi-Spec and Swagger-UI.
- * The url of the paths are already split at '/'.
- */
- var pathFilter: ((method: HttpMethod, url: List) -> Boolean)? = null
-
-
- /**
- * Swagger-UI configuration
- */
- fun swagger(block: SwaggerUIDsl.() -> Unit) {
- swaggerUI = SwaggerUIDsl().apply(block)
- }
-
- private var swaggerUI = SwaggerUIDsl()
-
- fun getSwaggerUI() = swaggerUI
-
-
- /**
- * OpenAPI info configuration - provides metadata about the API
- */
- fun info(block: OpenApiInfo.() -> Unit) {
- info = OpenApiInfo().apply(block)
- }
-
- private var info = OpenApiInfo()
-
- fun getInfo() = info
-
-
- /**
- * OpenAPI server configuration - an array of servers, which provide connectivity information to a target server
- */
- fun server(block: OpenApiServer.() -> Unit) {
- servers.add(OpenApiServer().apply(block))
- }
-
- private val servers = mutableListOf()
-
- fun getServers(): List = servers
-
-
- /**
- * OpenAPI external docs configuration - link and description of an external documentation
- */
- fun externalDocs(block: OpenApiExternalDocs.() -> Unit) {
- externalDocs = OpenApiExternalDocs().apply(block)
- }
-
- private var externalDocs = OpenApiExternalDocs()
-
- fun getExternalDocs() = externalDocs
-
-
- /**
- * Defines security schemes that can be used by operations
- */
- fun securityScheme(name: String, block: OpenApiSecurityScheme.() -> Unit) {
- securitySchemes.add(OpenApiSecurityScheme(name).apply(block))
- }
-
- private val securitySchemes = mutableListOf()
-
- fun getSecuritySchemes(): List = securitySchemes
-
-
- /**
- * Tags used by the specification with additional metadata. Not all tags that are used must be declared
- */
- fun tag(name: String, block: OpenApiTag.() -> Unit) {
- tags.add(OpenApiTag(name).apply(block))
- }
-
- private val tags = mutableListOf()
-
- fun getTags(): List = tags
-
-
- /**
- * Custom schemas to reference via [io.github.smiley4.ktorswaggerui.dsl.CustomSchemaRef]
- */
- fun customSchemas(block: CustomSchemas.() -> Unit) {
- this.customSchemas = CustomSchemas().apply(block)
- }
-
- private var customSchemas = CustomSchemas()
-
- fun getCustomSchemas() = customSchemas
-
-
- /**
- * customize the behaviour of different encoders (examples, schemas, ...)
- */
- fun encoding(block: EncodingConfig.() -> Unit) {
- block(encodingConfig)
- }
-
- val encodingConfig: EncodingConfig = EncodingConfig()
-
-
- /**
- * List of all [RouteSelector] types in that should be ignored in the resulting url of any route.
- */
- var ignoredRouteSelectors: List> = listOf()
-
-}
-
-/**
- * url - the parts of the route-url split at all `/`.
- * return a collection of tags. "Null"-entries will be ignored.
- */
-typealias TagGenerator = (url: List) -> Collection
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContext.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContext.kt
similarity index 94%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContext.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContext.kt
index 05dd8d5f..8c031c32 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContext.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContext.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.example
+package io.github.smiley4.ktorswaggerui.builder.example
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRequestParameter
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContextBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContextBuilder.kt
similarity index 61%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContextBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContextBuilder.kt
index 426ca98d..608eef52 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/example/ExampleContextBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/example/ExampleContextBuilder.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.example
+package io.github.smiley4.ktorswaggerui.builder.example
import io.github.smiley4.ktorswaggerui.dsl.OpenApiBaseBody
import io.github.smiley4.ktorswaggerui.dsl.OpenApiExample
@@ -7,8 +7,14 @@ import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponse
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
import io.github.smiley4.ktorswaggerui.dsl.SchemaType
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
-import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExampleBuilder
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CollectionBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CustomRefBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.EmptyBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.OneOfBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.SchemaBodyTypeDescriptor
import io.swagger.v3.oas.models.examples.Example
class ExampleContextBuilder(
@@ -42,7 +48,18 @@ class ExampleContextBuilder(
private fun handle(ctx: ExampleContext, body: OpenApiSimpleBody) {
body.getExamples().forEach { (name, value) ->
- ctx.addExample(body, name, createExample(body.type ?: getSchemaType(), value))
+ val bodyType = getRelevantSchemaType(body.type, getSchemaType())
+ ctx.addExample(body, name, createExample(bodyType, value))
+ }
+ }
+
+ private fun getRelevantSchemaType(typeDescriptor: BodyTypeDescriptor, fallback: SchemaType): SchemaType {
+ return when(typeDescriptor) {
+ is EmptyBodyTypeDescriptor -> fallback
+ is SchemaBodyTypeDescriptor -> typeDescriptor.schemaType
+ is CollectionBodyTypeDescriptor -> getRelevantSchemaType(typeDescriptor.schemaType, fallback)
+ is OneOfBodyTypeDescriptor -> fallback
+ is CustomRefBodyTypeDescriptor -> fallback
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ComponentsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ComponentsBuilder.kt
similarity index 67%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ComponentsBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ComponentsBuilder.kt
index 3847063a..7d09097b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ComponentsBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ComponentsBuilder.kt
@@ -1,12 +1,12 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
import io.swagger.v3.oas.models.Components
import io.swagger.v3.oas.models.examples.Example
import io.swagger.v3.oas.models.media.Schema
class ComponentsBuilder(
- private val config: SwaggerUIPluginConfig,
+ private val config: PluginConfigData,
private val securitySchemesBuilder: SecuritySchemesBuilder
) {
@@ -14,8 +14,8 @@ class ComponentsBuilder(
return Components().also {
it.schemas = schemas
it.examples = examples
- if (config.getSecuritySchemes().isNotEmpty()) {
- it.securitySchemes = securitySchemesBuilder.build(config.getSecuritySchemes())
+ if (config.securitySchemes.isNotEmpty()) {
+ it.securitySchemes = securitySchemesBuilder.build(config.securitySchemes)
}
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContactBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContactBuilder.kt
similarity index 57%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContactBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContactBuilder.kt
index 2d88df06..5fc0e483 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContactBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContactBuilder.kt
@@ -1,11 +1,11 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiContact
+import io.github.smiley4.ktorswaggerui.data.ContactData
import io.swagger.v3.oas.models.info.Contact
class ContactBuilder {
- fun build(contact: OpenApiContact): Contact =
+ fun build(contact: ContactData): Contact =
Contact().also {
it.name = contact.name
it.email = contact.email
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContentBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt
similarity index 73%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContentBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt
index 34896aa1..ee2bd7d5 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ContentBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ContentBuilder.kt
@@ -1,29 +1,23 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CollectionBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CustomRefBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.EmptyBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.OneOfBodyTypeDescriptor
import io.github.smiley4.ktorswaggerui.dsl.OpenApiBaseBody
import io.github.smiley4.ktorswaggerui.dsl.OpenApiMultipartBody
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
import io.github.smiley4.ktorswaggerui.dsl.OpenApiMultipartPart
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
+import io.github.smiley4.ktorswaggerui.dsl.SchemaBodyTypeDescriptor
import io.ktor.http.ContentType
import io.swagger.v3.oas.models.media.Content
import io.swagger.v3.oas.models.media.Encoding
import io.swagger.v3.oas.models.media.MediaType
import io.swagger.v3.oas.models.media.Schema
-import kotlin.collections.Map
-import kotlin.collections.MutableMap
-import kotlin.collections.associateWith
-import kotlin.collections.filter
-import kotlin.collections.flatMap
-import kotlin.collections.forEach
-import kotlin.collections.ifEmpty
-import kotlin.collections.isNotEmpty
-import kotlin.collections.joinToString
-import kotlin.collections.mapValues
-import kotlin.collections.mutableMapOf
import kotlin.collections.set
-import kotlin.collections.setOf
class ContentBuilder(
private val schemaContext: SchemaContext,
@@ -106,22 +100,37 @@ class ContentBuilder(
}
private fun getSchema(body: OpenApiSimpleBody): Schema<*>? {
- return if (body.customSchema != null) {
- schemaContext.getSchema(body.customSchema!!)
- } else if (body.type != null) {
- schemaContext.getSchema(body.type)
- } else {
- null
- }
+ return getSchema(body.type)
}
private fun getSchema(part: OpenApiMultipartPart): Schema<*>? {
- return if (part.customSchema != null) {
- schemaContext.getSchema(part.customSchema!!)
- } else if (part.type != null) {
- schemaContext.getSchema(part.type)
- } else {
- null
+ return getSchema(part.type)
+ }
+
+ private fun getSchema(typeDescriptor: BodyTypeDescriptor): Schema<*>? {
+ return when (typeDescriptor) {
+ is EmptyBodyTypeDescriptor -> {
+ null
+ }
+ is SchemaBodyTypeDescriptor -> {
+ schemaContext.getSchema(typeDescriptor.schemaType)
+ }
+ is OneOfBodyTypeDescriptor -> {
+ Schema().also { schema ->
+ typeDescriptor.elements.forEach {
+ schema.addOneOfItem(getSchema(it))
+ }
+ }
+ }
+ is CollectionBodyTypeDescriptor -> {
+ Schema().also { schema ->
+ schema.type = "array"
+ schema.items = getSchema(typeDescriptor.schemaType)
+ }
+ }
+ is CustomRefBodyTypeDescriptor -> {
+ schemaContext.getSchema(typeDescriptor.customSchemaId)
+ }
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExampleBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExampleBuilder.kt
similarity index 67%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExampleBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExampleBuilder.kt
index 864678c6..2b452fa1 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExampleBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExampleBuilder.kt
@@ -1,12 +1,12 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiExample
import io.github.smiley4.ktorswaggerui.dsl.SchemaType
import io.swagger.v3.oas.models.examples.Example
class ExampleBuilder(
- private val config: SwaggerUIPluginConfig
+ private val config: PluginConfigData
) {
fun build(type: SchemaType?, example: OpenApiExample): Example =
@@ -17,7 +17,7 @@ class ExampleBuilder(
}
fun buildExampleValue(type: SchemaType?, value: Any): String {
- return config.encodingConfig.getExampleEncoder()(type, value) ?: value.toString()
+ return config.encoding.exampleEncoder(type, value) ?: value.toString()
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExternalDocumentationBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExternalDocumentationBuilder.kt
similarity index 55%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExternalDocumentationBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExternalDocumentationBuilder.kt
index 7c463e4f..49f4fd2e 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ExternalDocumentationBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ExternalDocumentationBuilder.kt
@@ -1,11 +1,11 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiExternalDocs
+import io.github.smiley4.ktorswaggerui.data.ExternalDocsData
import io.swagger.v3.oas.models.ExternalDocumentation
class ExternalDocumentationBuilder {
- fun build(externalDocs: OpenApiExternalDocs): ExternalDocumentation =
+ fun build(externalDocs: ExternalDocsData): ExternalDocumentation =
ExternalDocumentation().also {
it.url = externalDocs.url
it.description = externalDocs.description
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/HeaderBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/HeaderBuilder.kt
similarity index 79%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/HeaderBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/HeaderBuilder.kt
index b9f2e11c..4c0fd1a7 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/HeaderBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/HeaderBuilder.kt
@@ -1,7 +1,7 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
import io.github.smiley4.ktorswaggerui.dsl.OpenApiHeader
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
import io.swagger.v3.oas.models.headers.Header
class HeaderBuilder(
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/InfoBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/InfoBuilder.kt
similarity index 67%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/InfoBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/InfoBuilder.kt
index 3c2b7a9f..bfc03dc2 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/InfoBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/InfoBuilder.kt
@@ -1,6 +1,6 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiInfo
+import io.github.smiley4.ktorswaggerui.data.InfoData
import io.swagger.v3.oas.models.info.Info
class InfoBuilder(
@@ -8,16 +8,16 @@ class InfoBuilder(
private val licenseBuilder: LicenseBuilder
) {
- fun build(info: OpenApiInfo): Info =
+ fun build(info: InfoData): Info =
Info().also {
it.title = info.title
it.version = info.version
it.description = info.description
it.termsOfService = info.termsOfService
- info.getContact()?.also { contact ->
+ info.contact?.also { contact ->
it.contact = contactBuilder.build(contact)
}
- info.getLicense()?.also { license ->
+ info.license?.also { license ->
it.license = licenseBuilder.build(license)
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/LicenseBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/LicenseBuilder.kt
similarity index 52%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/LicenseBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/LicenseBuilder.kt
index 968ea2fb..30f727c0 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/LicenseBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/LicenseBuilder.kt
@@ -1,11 +1,11 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiLicense
+import io.github.smiley4.ktorswaggerui.data.LicenseData
import io.swagger.v3.oas.models.info.License
class LicenseBuilder {
- fun build(license: OpenApiLicense): License =
+ fun build(license: LicenseData): License =
License().also {
it.name = license.name
it.url = license.url
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OAuthFlowsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OAuthFlowsBuilder.kt
new file mode 100644
index 00000000..c8f8c965
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OAuthFlowsBuilder.kt
@@ -0,0 +1,35 @@
+package io.github.smiley4.ktorswaggerui.builder.openapi
+
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowData
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowsData
+import io.swagger.v3.oas.models.security.OAuthFlow
+import io.swagger.v3.oas.models.security.OAuthFlows
+import io.swagger.v3.oas.models.security.Scopes
+
+class OAuthFlowsBuilder {
+
+ fun build(flows: OpenIdOAuthFlowsData): OAuthFlows {
+ return OAuthFlows().apply {
+ implicit = flows.implicit?.let { build(it) }
+ password = flows.password?.let { build(it) }
+ clientCredentials = flows.clientCredentials?.let { build(it) }
+ authorizationCode = flows.authorizationCode?.let { build(it) }
+ }
+ }
+
+ private fun build(flow: OpenIdOAuthFlowData): OAuthFlow {
+ return OAuthFlow().apply {
+ authorizationUrl = flow.authorizationUrl
+ tokenUrl = flow.tokenUrl
+ refreshUrl = flow.refreshUrl
+ scopes = flow.scopes?.let { buildScopes(it) }
+ }
+ }
+
+ private fun buildScopes(scopes: Map): Scopes {
+ return Scopes().apply {
+ scopes.forEach { (k, v) -> addString(k, v) }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OpenApiBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OpenApiBuilder.kt
similarity index 57%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OpenApiBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OpenApiBuilder.kt
index 0f1c6946..f3adac85 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OpenApiBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OpenApiBuilder.kt
@@ -1,13 +1,13 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
import io.swagger.v3.oas.models.OpenAPI
class OpenApiBuilder(
- private val config: SwaggerUIPluginConfig,
+ private val config: PluginConfigData,
private val schemaContext: SchemaContext,
private val exampleContext: ExampleContext,
private val infoBuilder: InfoBuilder,
@@ -20,10 +20,10 @@ class OpenApiBuilder(
fun build(routes: Collection): OpenAPI {
return OpenAPI().also {
- it.info = infoBuilder.build(config.getInfo())
- it.externalDocs = externalDocumentationBuilder.build(config.getExternalDocs())
- it.servers = config.getServers().map { server -> serverBuilder.build(server) }
- it.tags = config.getTags().map { tag -> tagBuilder.build(tag) }
+ it.info = infoBuilder.build(config.info)
+ it.externalDocs = externalDocumentationBuilder.build(config.externalDocs)
+ it.servers = config.servers.map { server -> serverBuilder.build(server) }
+ it.tags = config.tags.map { tag -> tagBuilder.build(tag) }
it.paths = pathsBuilder.build(routes)
it.components = componentsBuilder.build(schemaContext.getComponentsSection(), exampleContext.getComponentsSection())
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationBuilder.kt
similarity index 92%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationBuilder.kt
index 0b2df038..3e48ce88 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationBuilder.kt
@@ -1,6 +1,6 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.swagger.v3.oas.models.Operation
class OperationBuilder(
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationTagsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationTagsBuilder.kt
new file mode 100644
index 00000000..962ae049
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/OperationTagsBuilder.kt
@@ -0,0 +1,21 @@
+package io.github.smiley4.ktorswaggerui.builder.openapi
+
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+
+class OperationTagsBuilder(
+ private val config: PluginConfigData
+) {
+
+ fun build(route: RouteMeta): List {
+ return mutableSetOf().also { tags ->
+ tags.addAll(getGeneratedTags(route))
+ tags.addAll(getRouteTags(route))
+ }.filterNotNull()
+ }
+
+ private fun getRouteTags(route: RouteMeta) = route.documentation.tags
+
+ private fun getGeneratedTags(route: RouteMeta) = config.tagGenerator(route.path.split("/").filter { it.isNotEmpty() })
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ParameterBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ParameterBuilder.kt
similarity index 84%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ParameterBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ParameterBuilder.kt
index 8b7a811b..bbf76039 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ParameterBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ParameterBuilder.kt
@@ -1,8 +1,8 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRequestParameter
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
import io.swagger.v3.oas.models.parameters.Parameter
class ParameterBuilder(
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathBuilder.kt
similarity index 86%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathBuilder.kt
index a77b865f..a6c5c93e 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathBuilder.kt
@@ -1,6 +1,6 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.ktor.http.HttpMethod
import io.swagger.v3.oas.models.PathItem
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathsBuilder.kt
similarity index 91%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathsBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathsBuilder.kt
index 615d45d3..46a3c6eb 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/PathsBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/PathsBuilder.kt
@@ -1,6 +1,6 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.swagger.v3.oas.models.PathItem
import io.swagger.v3.oas.models.Paths
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/RequestBodyBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/RequestBodyBuilder.kt
similarity index 88%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/RequestBodyBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/RequestBodyBuilder.kt
index 189fada8..f5a6383b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/RequestBodyBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/RequestBodyBuilder.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
import io.github.smiley4.ktorswaggerui.dsl.OpenApiBaseBody
import io.swagger.v3.oas.models.parameters.RequestBody
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponseBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponseBuilder.kt
similarity index 91%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponseBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponseBuilder.kt
index 66cf191d..7e59eec0 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponseBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponseBuilder.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponse
import io.swagger.v3.oas.models.responses.ApiResponse
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponsesBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponsesBuilder.kt
similarity index 79%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponsesBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponsesBuilder.kt
index 8a95d268..bd148dd7 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ResponsesBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ResponsesBuilder.kt
@@ -1,13 +1,13 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponses
import io.ktor.http.HttpStatusCode
import io.swagger.v3.oas.models.responses.ApiResponses
class ResponsesBuilder(
private val responseBuilder: ResponseBuilder,
- private val config: SwaggerUIPluginConfig
+ private val config: PluginConfigData
) {
fun build(responses: OpenApiResponses, isProtected: Boolean): ApiResponses =
@@ -16,7 +16,7 @@ class ResponsesBuilder(
.map { response -> responseBuilder.build(response) }
.forEach { (name, response) -> it.addApiResponse(name, response) }
if (shouldAddUnauthorized(responses, isProtected)) {
- config.getDefaultUnauthorizedResponse()
+ config.defaultUnauthorizedResponse
?.let { response -> responseBuilder.build(response) }
?.also { (name, response) -> it.addApiResponse(name, response) }
}
@@ -24,7 +24,7 @@ class ResponsesBuilder(
private fun shouldAddUnauthorized(responses: OpenApiResponses, isProtected: Boolean): Boolean {
val unauthorizedCode = HttpStatusCode.Unauthorized.value.toString();
- return config.getDefaultUnauthorizedResponse() != null
+ return config.defaultUnauthorizedResponse != null
&& isProtected
&& responses.getResponses().count { it.statusCode == unauthorizedCode } == 0
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecurityRequirementsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecurityRequirementsBuilder.kt
similarity index 61%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecurityRequirementsBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecurityRequirementsBuilder.kt
index 473bdef7..3b1df677 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecurityRequirementsBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecurityRequirementsBuilder.kt
@@ -1,11 +1,11 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.swagger.v3.oas.models.security.SecurityRequirement
class SecurityRequirementsBuilder(
- private val config: SwaggerUIPluginConfig
+ private val config: PluginConfigData
) {
fun build(route: RouteMeta): List {
@@ -14,8 +14,7 @@ class SecurityRequirementsBuilder(
route.documentation.securitySchemeNames?.also { schemes.addAll(it) }
}
if (securitySchemes.isEmpty()) {
- config.defaultSecuritySchemeName?.also { securitySchemes.add(it) }
- config.defaultSecuritySchemeNames?.also { securitySchemes.addAll(it) }
+ config.defaultSecuritySchemeNames.also { securitySchemes.addAll(it) }
}
return securitySchemes.map {
SecurityRequirement().apply {
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecuritySchemesBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecuritySchemesBuilder.kt
similarity index 66%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecuritySchemesBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecuritySchemesBuilder.kt
index 017720bf..9216f0fe 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/SecuritySchemesBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/SecuritySchemesBuilder.kt
@@ -1,13 +1,13 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiSecurityScheme
+import io.github.smiley4.ktorswaggerui.data.SecuritySchemeData
import io.swagger.v3.oas.models.security.SecurityScheme
class SecuritySchemesBuilder(
private val oAuthFlowsBuilder: OAuthFlowsBuilder
) {
- fun build(securitySchemes: List): Map {
+ fun build(securitySchemes: List): Map {
return mutableMapOf().apply {
securitySchemes.forEach {
put(it.name, build(it))
@@ -15,7 +15,7 @@ class SecuritySchemesBuilder(
}
}
- private fun build(securityScheme: OpenApiSecurityScheme): SecurityScheme {
+ private fun build(securityScheme: SecuritySchemeData): SecurityScheme {
return SecurityScheme().apply {
description = securityScheme.description
name = securityScheme.name
@@ -23,7 +23,7 @@ class SecuritySchemesBuilder(
`in` = securityScheme.location?.swaggerType
scheme = securityScheme.scheme?.swaggerType
bearerFormat = securityScheme.bearerFormat
- flows = securityScheme.getFlows()?.let { f -> oAuthFlowsBuilder.build(f) }
+ flows = securityScheme.flows?.let { f -> oAuthFlowsBuilder.build(f) }
openIdConnectUrl = securityScheme.openIdConnectUrl
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ServerBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ServerBuilder.kt
similarity index 54%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ServerBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ServerBuilder.kt
index 84196d42..5878483f 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/ServerBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/ServerBuilder.kt
@@ -1,11 +1,11 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiServer
+import io.github.smiley4.ktorswaggerui.data.ServerData
import io.swagger.v3.oas.models.servers.Server
class ServerBuilder {
- fun build(server: OpenApiServer): Server =
+ fun build(server: ServerData): Server =
Server().also {
it.url = server.url
it.description = server.description
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagBuilder.kt
similarity index 67%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagBuilder.kt
index 60284d77..d550e6a3 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagBuilder.kt
@@ -1,18 +1,18 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
-import io.github.smiley4.ktorswaggerui.dsl.OpenApiTag
+import io.github.smiley4.ktorswaggerui.data.TagData
import io.swagger.v3.oas.models.tags.Tag
class TagBuilder(
private val tagExternalDocumentationBuilder: TagExternalDocumentationBuilder
) {
- fun build(tag: OpenApiTag): Tag =
+ fun build(tag: TagData): Tag =
Tag().also {
it.name = tag.name
it.description = tag.description
if(tag.externalDocUrl != null && tag.externalDocDescription != null) {
- it.externalDocs = tagExternalDocumentationBuilder.build(tag.externalDocUrl!!, tag.externalDocDescription!!)
+ it.externalDocs = tagExternalDocumentationBuilder.build(tag.externalDocUrl, tag.externalDocDescription)
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagExternalDocumentationBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagExternalDocumentationBuilder.kt
similarity index 83%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagExternalDocumentationBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagExternalDocumentationBuilder.kt
index 805cd313..4e53c08b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/TagExternalDocumentationBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/openapi/TagExternalDocumentationBuilder.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
+package io.github.smiley4.ktorswaggerui.builder.openapi
import io.swagger.v3.oas.models.ExternalDocumentation
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteCollector.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt
similarity index 76%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteCollector.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt
index 4fac4256..040af3cc 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteCollector.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt
@@ -1,6 +1,6 @@
-package io.github.smiley4.ktorswaggerui.spec.route
+package io.github.smiley4.ktorswaggerui.builder.route
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
import io.github.smiley4.ktorswaggerui.dsl.DocumentedRouteSelector
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
import io.ktor.http.HttpMethod
@@ -19,7 +19,7 @@ class RouteCollector(
/**
* Collect all routes from the given application
*/
- fun collectRoutes(routeProvider: () -> Route, config: SwaggerUIPluginConfig): Sequence {
+ fun collectRoutes(routeProvider: () -> Route, config: PluginConfigData): Sequence {
return allRoutes(routeProvider())
.asSequence()
.map { route ->
@@ -31,25 +31,10 @@ class RouteCollector(
protected = documentation.protected ?: isProtected(route)
)
}
- .filter { removeLeadingSlash(it.path) != removeLeadingSlash(config.getSwaggerUI().swaggerUrl) }
- .filter { removeLeadingSlash(it.path) != removeLeadingSlash("${config.getSwaggerUI().swaggerUrl}/api.json") }
- .filter { removeLeadingSlash(it.path) != removeLeadingSlash("${config.getSwaggerUI().swaggerUrl}/{filename}") }
- .filter { !config.getSwaggerUI().forwardRoot || it.path != "/" }
.filter { !it.documentation.hidden }
- .filter { path ->
- config.pathFilter
- ?.let { it(path.method, path.path.split("/").filter { it.isNotEmpty() }) }
- ?: true
- }
+ .filter { path -> config.pathFilter(path.method, path.path.split("/").filter { it.isNotEmpty() }) }
}
- private fun removeLeadingSlash(str: String): String =
- if (str.startsWith("/")) {
- str.substring(1)
- } else {
- str
- }
-
private fun getDocumentation(route: Route, base: OpenApiRoute): OpenApiRoute {
var documentation = base
if (route.selector is DocumentedRouteSelector) {
@@ -67,7 +52,7 @@ class RouteCollector(
return (route.selector as HttpMethodRouteSelector).method
}
- private fun getPath(route: Route, config: SwaggerUIPluginConfig): String {
+ private fun getPath(route: Route, config: PluginConfigData): String {
val selector = route.selector
return if (isIgnoredSelector(selector, config)) {
route.parent?.let { getPath(it, config) } ?: ""
@@ -83,7 +68,7 @@ class RouteCollector(
}
}
- private fun isIgnoredSelector(selector: RouteSelector, config: SwaggerUIPluginConfig): Boolean {
+ private fun isIgnoredSelector(selector: RouteSelector, config: PluginConfigData): Boolean {
return when (selector) {
is TrailingSlashRouteSelector -> false
is RootRouteSelector -> false
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteDocumentationMerger.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteDocumentationMerger.kt
similarity index 87%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteDocumentationMerger.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteDocumentationMerger.kt
index 6c4cf509..f0509b9b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteDocumentationMerger.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteDocumentationMerger.kt
@@ -1,11 +1,15 @@
-package io.github.smiley4.ktorswaggerui.spec.route
+package io.github.smiley4.ktorswaggerui.builder.route
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
class RouteDocumentationMerger {
+ /**
+ * Merges "a" with "b" and returns the result as a new [OpenApiRoute]. "a" has priority over "b".
+ */
fun merge(a: OpenApiRoute, b: OpenApiRoute): OpenApiRoute {
return OpenApiRoute().apply {
+ specId = a.specId ?: b.specId
tags = mutableListOf().also {
it.addAll(a.tags)
it.addAll(b.tags)
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteMeta.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteMeta.kt
similarity index 83%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteMeta.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteMeta.kt
index e7975984..21452920 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/route/RouteMeta.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteMeta.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.route
+package io.github.smiley4.ktorswaggerui.builder.route
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
import io.ktor.http.HttpMethod
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaBuilder.kt
similarity index 98%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaBuilder.kt
index e7f50baa..5d85e608 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaBuilder.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.schema
+package io.github.smiley4.ktorswaggerui.builder.schema
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContext.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContext.kt
similarity index 93%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContext.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContext.kt
index 4fb81fdf..ab0f9a56 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContext.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContext.kt
@@ -1,12 +1,10 @@
-package io.github.smiley4.ktorswaggerui.spec.schema
+package io.github.smiley4.ktorswaggerui.builder.schema
-import io.github.smiley4.ktorswaggerui.dsl.CustomSchemaRef
import io.github.smiley4.ktorswaggerui.dsl.SchemaType
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
import io.github.smiley4.ktorswaggerui.dsl.getSimpleArrayElementTypeName
import io.github.smiley4.ktorswaggerui.dsl.getSimpleTypeName
import io.swagger.v3.oas.models.media.Schema
-import java.lang.IllegalArgumentException
import kotlin.collections.set
@@ -52,22 +50,24 @@ class SchemaContext {
}
- fun addSchema(ref: CustomSchemaRef, schema: SchemaDefinitions) {
- schemasCustom[ref.schemaId] = schema
+ fun addSchema(customSchemaId: String, schema: SchemaDefinitions) {
+ schemasCustom[customSchemaId] = schema
}
fun getComponentsSection(): Map> = componentsSection
- fun getSchema(type: SchemaType) = getSchemaOrNull(type) ?: throw NoSuchElementException ("No schema for type '$type'!")
+ fun getSchema(type: SchemaType) = getSchemaOrNull(type)
+ ?: throw NoSuchElementException("No schema for type '$type'!")
fun getSchemaOrNull(type: SchemaType) = inlineSchemas[type]
- fun getSchema(ref: CustomSchemaRef) = getSchemaOrNull(ref) ?: throw NoSuchElementException("No schema for ref '$ref'!")
+ fun getSchema(customSchemaId: String) = getSchemaOrNull(customSchemaId)
+ ?: throw NoSuchElementException("No schema for ref '$customSchemaId'!")
- fun getSchemaOrNull(ref: CustomSchemaRef) = inlineSchemasCustom[ref.schemaId]
+ fun getSchemaOrNull(customSchemaId: String) = inlineSchemasCustom[customSchemaId]
fun finalize() {
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContextBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContextBuilder.kt
similarity index 59%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContextBuilder.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContextBuilder.kt
index 923526a9..3dbea962 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaContextBuilder.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaContextBuilder.kt
@@ -1,24 +1,27 @@
-package io.github.smiley4.ktorswaggerui.spec.schema
-
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
-import io.github.smiley4.ktorswaggerui.dsl.BaseCustomSchema
-import io.github.smiley4.ktorswaggerui.dsl.CustomArraySchemaRef
-import io.github.smiley4.ktorswaggerui.dsl.CustomJsonSchema
-import io.github.smiley4.ktorswaggerui.dsl.CustomOpenApiSchema
-import io.github.smiley4.ktorswaggerui.dsl.CustomSchemaRef
+package io.github.smiley4.ktorswaggerui.builder.schema
+
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.data.BaseCustomSchema
+import io.github.smiley4.ktorswaggerui.data.CustomJsonSchema
+import io.github.smiley4.ktorswaggerui.data.CustomOpenApiSchema
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.data.RemoteSchema
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CollectionBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.CustomRefBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.EmptyBodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.OneOfBodyTypeDescriptor
import io.github.smiley4.ktorswaggerui.dsl.OpenApiBaseBody
import io.github.smiley4.ktorswaggerui.dsl.OpenApiMultipartBody
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRequestParameter
import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponse
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
-import io.github.smiley4.ktorswaggerui.dsl.RemoteSchema
+import io.github.smiley4.ktorswaggerui.dsl.SchemaBodyTypeDescriptor
import io.github.smiley4.ktorswaggerui.dsl.SchemaType
-import io.github.smiley4.ktorswaggerui.dsl.obj
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
import io.swagger.v3.oas.models.media.Schema
class SchemaContextBuilder(
- private val config: SwaggerUIPluginConfig,
+ private val config: PluginConfigData,
private val schemaBuilder: SchemaBuilder
) {
@@ -26,9 +29,9 @@ class SchemaContextBuilder(
return SchemaContext()
.also { ctx -> routes.forEach { handle(ctx, it) } }
.also { ctx ->
- if (config.getCustomSchemas().includeAll) {
- config.getCustomSchemas().getSchemas().forEach { (id, schema) ->
- ctx.addSchema(obj(id), createSchema(schema, false))
+ if (config.includeAllCustomSchemas) {
+ config.customSchemas.forEach { (id, schema) ->
+ ctx.addSchema(id, createSchema(schema))
}
}
}
@@ -62,20 +65,29 @@ class SchemaContextBuilder(
private fun handle(ctx: SchemaContext, body: OpenApiSimpleBody) {
- if (body.customSchema != null) {
- body.customSchema?.also { ctx.addSchema(it, createSchema(it)) }
- } else {
- body.type?.also { ctx.addSchema(it, createSchema(it)) }
- }
+ addSchemas(ctx, body.type)
}
-
private fun handle(ctx: SchemaContext, body: OpenApiMultipartBody) {
body.getParts().forEach { part ->
- if (part.customSchema != null) {
- part.customSchema?.also { ctx.addSchema(it, createSchema(it)) }
- } else {
- part.type?.also { ctx.addSchema(it, createSchema(it)) }
+ part.type.also { addSchemas(ctx, part.type) }
+ }
+ }
+
+ private fun addSchemas(ctx: SchemaContext, typeDescriptor: BodyTypeDescriptor) {
+ when (typeDescriptor) {
+ is EmptyBodyTypeDescriptor -> Unit
+ is SchemaBodyTypeDescriptor -> {
+ ctx.addSchema(typeDescriptor.schemaType, createSchema(typeDescriptor.schemaType))
+ }
+ is CollectionBodyTypeDescriptor -> {
+ addSchemas(ctx, typeDescriptor.schemaType)
+ }
+ is OneOfBodyTypeDescriptor -> {
+ typeDescriptor.elements.forEach { addSchemas(ctx, it) }
+ }
+ is CustomRefBodyTypeDescriptor -> {
+ ctx.addSchema(typeDescriptor.customSchemaId, createSchema(typeDescriptor.customSchemaId))
}
}
}
@@ -91,20 +103,20 @@ class SchemaContextBuilder(
}
- private fun createSchema(customSchemaRef: CustomSchemaRef): SchemaDefinitions {
- val customSchema = config.getCustomSchemas().getSchema(customSchemaRef.schemaId)
+ private fun createSchema(customSchemaId: String): SchemaDefinitions {
+ val customSchema = config.customSchemas[customSchemaId]
return if (customSchema == null) {
SchemaDefinitions(
root = Schema(),
definitions = emptyMap()
)
} else {
- createSchema(customSchema, customSchemaRef is CustomArraySchemaRef)
+ createSchema(customSchema)
}
}
- private fun createSchema(customSchema: BaseCustomSchema, isArray: Boolean): SchemaDefinitions {
+ private fun createSchema(customSchema: BaseCustomSchema): SchemaDefinitions {
return when (customSchema) {
is CustomJsonSchema -> {
schemaBuilder.create(customSchema.provider())
@@ -125,18 +137,6 @@ class SchemaContextBuilder(
definitions = emptyMap()
)
}
- }.let { schemaDefinitions ->
- if (isArray) {
- SchemaDefinitions(
- root = Schema().apply {
- type = "array"
- items = schemaDefinitions.root
- },
- definitions = schemaDefinitions.definitions
- )
- } else {
- schemaDefinitions
- }
}
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaTypeAttributeOverride.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaTypeAttributeOverride.kt
similarity index 95%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaTypeAttributeOverride.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaTypeAttributeOverride.kt
index 0fc80fca..f160b369 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/SchemaTypeAttributeOverride.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/SchemaTypeAttributeOverride.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.schema
+package io.github.smiley4.ktorswaggerui.builder.schema
import com.fasterxml.jackson.databind.node.ObjectNode
import com.github.victools.jsonschema.generator.FieldScope
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/TypeOverwrites.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/TypeOverwrites.kt
similarity index 88%
rename from src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/TypeOverwrites.kt
rename to src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/TypeOverwrites.kt
index 12bbae0f..c74646f3 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/schema/TypeOverwrites.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/schema/TypeOverwrites.kt
@@ -1,4 +1,4 @@
-package io.github.smiley4.ktorswaggerui.spec.schema
+package io.github.smiley4.ktorswaggerui.builder.schema
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
import java.io.File
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthKeyLocation.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthKeyLocation.kt
new file mode 100644
index 00000000..d94ab76a
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthKeyLocation.kt
@@ -0,0 +1,9 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import io.swagger.v3.oas.models.security.SecurityScheme
+
+enum class AuthKeyLocation(val swaggerType: SecurityScheme.In) {
+ QUERY(SecurityScheme.In.QUERY),
+ HEADER(SecurityScheme.In.HEADER),
+ COOKIE(SecurityScheme.In.COOKIE)
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthScheme.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthScheme.kt
new file mode 100644
index 00000000..e90593d8
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthScheme.kt
@@ -0,0 +1,14 @@
+package io.github.smiley4.ktorswaggerui.data
+
+// https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
+enum class AuthScheme(val swaggerType: String) {
+ BASIC("Basic"),
+ BEARER("Bearer"),
+ DIGEST("Digest"),
+ HOBA("HOBA"),
+ MUTUAL("Mutual"),
+ OAUTH("OAuth"),
+ SCRAM_SHA_1("SCRAM-SHA-1"),
+ SCRAM_SHA_256("SCRAM-SHA-256"),
+ VAPID("vapid")
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthType.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthType.kt
new file mode 100644
index 00000000..897ae471
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/AuthType.kt
@@ -0,0 +1,11 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import io.swagger.v3.oas.models.security.SecurityScheme
+
+enum class AuthType(val swaggerType: SecurityScheme.Type) {
+ API_KEY(SecurityScheme.Type.APIKEY),
+ HTTP(SecurityScheme.Type.HTTP),
+ OAUTH2(SecurityScheme.Type.OAUTH2),
+ OPENID_CONNECT(SecurityScheme.Type.OPENIDCONNECT),
+ MUTUAL_TLS(SecurityScheme.Type.MUTUALTLS)
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/BaseCustomSchema.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/BaseCustomSchema.kt
new file mode 100644
index 00000000..5be9f7fa
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/BaseCustomSchema.kt
@@ -0,0 +1,11 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import io.swagger.v3.oas.models.media.Schema
+
+sealed class BaseCustomSchema
+
+class CustomJsonSchema(val provider: () -> String) : BaseCustomSchema()
+
+class CustomOpenApiSchema(val provider: () -> Schema) : BaseCustomSchema()
+
+class RemoteSchema(val url: String) : BaseCustomSchema()
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ContactData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ContactData.kt
new file mode 100644
index 00000000..4a5f6968
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ContactData.kt
@@ -0,0 +1,15 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class ContactData(
+ val name: String?,
+ val url: String?,
+ val email: String?
+) {
+ companion object {
+ val DEFAULT = ContactData(
+ name = null,
+ url = null,
+ email = null
+ )
+ }
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/DataUtils.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/DataUtils.kt
new file mode 100644
index 00000000..0a59d037
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/DataUtils.kt
@@ -0,0 +1,11 @@
+package io.github.smiley4.ktorswaggerui.data
+
+object DataUtils {
+
+ fun mergeBoolean(base: Boolean, value: Boolean) = if (value) true else base
+
+ fun mergeDefault(base: T, value: T, default: T) = if (value != default) value else base
+
+ fun merge(base: T?, value: T?) = value ?: base
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/EncodingData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/EncodingData.kt
new file mode 100644
index 00000000..a87c9245
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/EncodingData.kt
@@ -0,0 +1,99 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import com.github.victools.jsonschema.generator.Option
+import com.github.victools.jsonschema.generator.OptionPreset
+import com.github.victools.jsonschema.generator.SchemaGenerator
+import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder
+import com.github.victools.jsonschema.generator.SchemaVersion
+import com.github.victools.jsonschema.module.jackson.JacksonModule
+import com.github.victools.jsonschema.module.swagger2.Swagger2Module
+import io.github.smiley4.ktorswaggerui.dsl.ExampleEncoder
+import io.github.smiley4.ktorswaggerui.dsl.SchemaEncoder
+import io.github.smiley4.ktorswaggerui.dsl.SchemaType
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaTypeAttributeOverride
+import kotlin.reflect.jvm.javaType
+
+data class EncodingData(
+ val exampleEncoder: ExampleEncoder,
+ val schemaEncoder: SchemaEncoder,
+ val schemaDefsField: String
+) {
+
+ companion object {
+ val DEFAULT = EncodingData(
+ exampleEncoder = defaultExampleEncoder(),
+ schemaEncoder = defaultSchemaEncoder(),
+ schemaDefsField = "\$defs"
+ )
+
+
+ /**
+ * The default jackson object mapper used for encoding examples to json.
+ */
+ var DEFAULT_EXAMPLE_OBJECT_MAPPER = jacksonObjectMapper()
+
+
+ /**
+ * The default [SchemaGenerator] used to encode types to json-schema.
+ * See https://victools.github.io/jsonschema-generator/#generator-options for more information.
+ */
+ var DEFAULT_SCHEMA_GENERATOR = SchemaGenerator(schemaGeneratorConfigBuilder().build())
+
+
+ /**
+ * The default [ExampleEncoder]
+ */
+ fun defaultExampleEncoder(): ExampleEncoder {
+ return { _, value -> encodeExample(value) }
+ }
+
+
+ /**
+ * encode the given value to a json string
+ */
+ fun encodeExample(value: Any?): String {
+ return if (value is String) {
+ value
+ } else {
+ DEFAULT_EXAMPLE_OBJECT_MAPPER.writeValueAsString(value)
+ }
+ }
+
+
+ /**
+ * The default [SchemaEncoder]
+ */
+ fun defaultSchemaEncoder(): SchemaEncoder {
+ return { type -> encodeSchema(type) }
+ }
+
+
+ /**
+ * encode the given type to a json-schema
+ */
+ fun encodeSchema(type: SchemaType): String {
+ return DEFAULT_SCHEMA_GENERATOR.generateSchema(type.javaType).toPrettyString()
+ }
+
+
+ /**
+ * The default [SchemaGeneratorConfigBuilder]
+ */
+ fun schemaGeneratorConfigBuilder(): SchemaGeneratorConfigBuilder =
+ SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON)
+ .with(JacksonModule())
+ .with(Swagger2Module())
+ .with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
+ .with(Option.ALLOF_CLEANUP_AT_THE_END)
+ .with(Option.MAP_VALUES_AS_ADDITIONAL_PROPERTIES)
+ .with(Option.DEFINITIONS_FOR_ALL_OBJECTS)
+ .without(Option.INLINE_ALL_SCHEMAS)
+ .also {
+ it.forTypesInGeneral()
+ .withTypeAttributeOverride(SchemaTypeAttributeOverride())
+ }
+
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ExternalDocsData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ExternalDocsData.kt
new file mode 100644
index 00000000..8ef5db07
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ExternalDocsData.kt
@@ -0,0 +1,15 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class ExternalDocsData(
+ val url: String,
+ val description: String?,
+) {
+
+ companion object {
+ val DEFAULT = ExternalDocsData(
+ url = "/",
+ description = null
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/InfoData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/InfoData.kt
new file mode 100644
index 00000000..fe8e1642
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/InfoData.kt
@@ -0,0 +1,21 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class InfoData(
+ val title: String,
+ val version: String?,
+ val description: String?,
+ val termsOfService: String?,
+ val contact: ContactData?,
+ val license: LicenseData?
+) {
+ companion object {
+ val DEFAULT = InfoData(
+ title = "API",
+ version = null,
+ description = null,
+ termsOfService = null,
+ contact = null,
+ license = null
+ )
+ }
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/LicenseData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/LicenseData.kt
new file mode 100644
index 00000000..154be47b
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/LicenseData.kt
@@ -0,0 +1,13 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class LicenseData(
+ val name: String?,
+ val url: String?,
+) {
+ companion object {
+ val DEFAULT = LicenseData(
+ name = null,
+ url = null,
+ )
+ }
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowData.kt
new file mode 100644
index 00000000..3072dec0
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowData.kt
@@ -0,0 +1,19 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class OpenIdOAuthFlowData(
+ val authorizationUrl: String? = null,
+ val tokenUrl: String? = null,
+ val refreshUrl: String? = null,
+ val scopes: Map? = null,
+) {
+
+ companion object {
+ val DEFAULT = OpenIdOAuthFlowData(
+ authorizationUrl = null,
+ tokenUrl = null,
+ refreshUrl = null,
+ scopes = null,
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowsData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowsData.kt
new file mode 100644
index 00000000..44acedf5
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/OpenIdOAuthFlowsData.kt
@@ -0,0 +1,19 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class OpenIdOAuthFlowsData(
+ val implicit: OpenIdOAuthFlowData?,
+ val password: OpenIdOAuthFlowData?,
+ val clientCredentials: OpenIdOAuthFlowData?,
+ val authorizationCode: OpenIdOAuthFlowData?,
+) {
+
+ companion object {
+ val DEFAULT = OpenIdOAuthFlowsData(
+ implicit = null,
+ password = null,
+ clientCredentials = null,
+ authorizationCode = null,
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PathFilter.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PathFilter.kt
new file mode 100644
index 00000000..73a75534
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PathFilter.kt
@@ -0,0 +1,6 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import io.ktor.http.HttpMethod
+
+
+typealias PathFilter = (method: HttpMethod, url: List) -> Boolean
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PluginConfigData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PluginConfigData.kt
new file mode 100644
index 00000000..0e5a605f
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/PluginConfigData.kt
@@ -0,0 +1,47 @@
+package io.github.smiley4.ktorswaggerui.data
+
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
+import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponse
+import kotlin.reflect.KClass
+
+data class PluginConfigData(
+ val defaultUnauthorizedResponse: OpenApiResponse?,
+ val defaultSecuritySchemeNames: Set,
+ val tagGenerator: TagGenerator,
+ val specAssigner: SpecAssigner,
+ val pathFilter: PathFilter,
+ val ignoredRouteSelectors: Set>,
+ val swaggerUI: SwaggerUIData,
+ val info: InfoData,
+ val servers: List,
+ val externalDocs: ExternalDocsData,
+ val securitySchemes: List,
+ val tags: List,
+ val customSchemas: Map,
+ val includeAllCustomSchemas: Boolean,
+ val encoding: EncodingData,
+ val specConfigs: MutableMap
+) {
+
+ companion object {
+ val DEFAULT = PluginConfigData(
+ defaultUnauthorizedResponse = null,
+ defaultSecuritySchemeNames = emptySet(),
+ tagGenerator = { emptyList() },
+ specAssigner = { _, _ -> PluginConfigDsl.DEFAULT_SPEC_ID },
+ pathFilter = { _, _ -> true },
+ ignoredRouteSelectors = emptySet(),
+ swaggerUI = SwaggerUIData.DEFAULT,
+ info = InfoData.DEFAULT,
+ servers = emptyList(),
+ externalDocs = ExternalDocsData.DEFAULT,
+ securitySchemes = emptyList(),
+ tags = emptyList(),
+ customSchemas = emptyMap(),
+ includeAllCustomSchemas = false,
+ encoding = EncodingData.DEFAULT,
+ specConfigs = mutableMapOf()
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SecuritySchemeData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SecuritySchemeData.kt
new file mode 100644
index 00000000..1e46bcaf
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SecuritySchemeData.kt
@@ -0,0 +1,27 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class SecuritySchemeData(
+ val name: String,
+ val type: AuthType?,
+ val location: AuthKeyLocation?,
+ val scheme: AuthScheme?,
+ val bearerFormat: String?,
+ val flows: OpenIdOAuthFlowsData?,
+ val openIdConnectUrl: String?,
+ val description: String?
+) {
+
+ companion object {
+ val DEFAULT = SecuritySchemeData(
+ name = "",
+ type = null,
+ location = null,
+ scheme = null,
+ bearerFormat = null,
+ flows = null,
+ openIdConnectUrl = null,
+ description = null,
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ServerData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ServerData.kt
new file mode 100644
index 00000000..a98ca613
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/ServerData.kt
@@ -0,0 +1,15 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class ServerData(
+ val url: String,
+ val description: String?,
+) {
+
+ companion object {
+ val DEFAULT = ServerData(
+ url = "/",
+ description = null
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SpecAssigned.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SpecAssigned.kt
new file mode 100644
index 00000000..28a5e840
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SpecAssigned.kt
@@ -0,0 +1,7 @@
+package io.github.smiley4.ktorswaggerui.data
+
+/**
+ * url - the parts of the route-url split at all `/`.
+ * tags - the tags assigned to the route
+ */
+typealias SpecAssigner = (url: String, tags: List) -> String
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUIData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUIData.kt
new file mode 100644
index 00000000..2b7014cf
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUIData.kt
@@ -0,0 +1,29 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class SwaggerUIData(
+ val forwardRoot: Boolean,
+ val swaggerUrl: String,
+ val rootHostPath: String,
+ val authentication: String?,
+ val validatorUrl: String?,
+ val displayOperationId: Boolean,
+ val showTagFilterInput: Boolean,
+ val sort: SwaggerUiSort,
+ val syntaxHighlight: SwaggerUiSyntaxHighlight
+) {
+
+ companion object {
+ val DEFAULT = SwaggerUIData(
+ forwardRoot = false,
+ swaggerUrl = "swagger-ui",
+ rootHostPath = "",
+ authentication = null,
+ validatorUrl = null,
+ displayOperationId = false,
+ showTagFilterInput = false,
+ sort = SwaggerUiSort.NONE,
+ syntaxHighlight = SwaggerUiSyntaxHighlight.AGATE
+ )
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSort.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSort.kt
new file mode 100644
index 00000000..84a40b13
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSort.kt
@@ -0,0 +1,20 @@
+package io.github.smiley4.ktorswaggerui.data
+
+enum class SwaggerUiSort(val value: String) {
+ /**
+ * The order returned by the server unchanged
+ */
+ NONE("undefined"),
+
+
+ /**
+ * sort by paths alphanumerically
+ */
+ ALPHANUMERICALLY("alpha"),
+
+
+ /**
+ * sort by HTTP method
+ */
+ HTTP_METHOD("method")
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSyntaxHighlight.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSyntaxHighlight.kt
new file mode 100644
index 00000000..749adf29
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/SwaggerUiSyntaxHighlight.kt
@@ -0,0 +1,10 @@
+package io.github.smiley4.ktorswaggerui.data
+
+enum class SwaggerUiSyntaxHighlight(val value: String) {
+ AGATE("agate"),
+ ARTA("arta"),
+ MONOKAI("monokai"),
+ NORD("nord"),
+ OBSIDIAN("obsidian"),
+ TOMORROW_NIGHT("tomorrow-night")
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagData.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagData.kt
new file mode 100644
index 00000000..29b30b6a
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagData.kt
@@ -0,0 +1,18 @@
+package io.github.smiley4.ktorswaggerui.data
+
+data class TagData(
+ val name: String,
+ val description: String?,
+ val externalDocDescription: String?,
+ val externalDocUrl: String?
+) {
+
+ companion object {
+ val DEFAULT = TagData(
+ name = "",
+ description = null,
+ externalDocDescription = null,
+ externalDocUrl = null
+ )
+ }
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagGenerator.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagGenerator.kt
new file mode 100644
index 00000000..6ba542bb
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/data/TagGenerator.kt
@@ -0,0 +1,7 @@
+package io.github.smiley4.ktorswaggerui.data
+
+/**
+ * url - the parts of the route-url split at all `/`.
+ * return a collection of tags. "Null"-entries will be ignored.
+ */
+typealias TagGenerator = (url: List) -> Collection
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/BodyTypeDescriptor.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/BodyTypeDescriptor.kt
new file mode 100644
index 00000000..72d74f88
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/BodyTypeDescriptor.kt
@@ -0,0 +1,130 @@
+package io.github.smiley4.ktorswaggerui.dsl
+
+import kotlin.reflect.KClass
+
+/**
+ * Describes the type/schema of a request or response body.
+ * [BodyTypeDescriptor]s can be nested to build more specific bodies from simple types
+ */
+sealed interface BodyTypeDescriptor {
+
+ companion object {
+
+ /**
+ * A [BodyTypeDescriptor] of the specific given type (or empty if type is null).
+ */
+ fun typeOf(type: KClass<*>?) = type?.let { SchemaBodyTypeDescriptor(it.asSchemaType()) } ?: EmptyBodyTypeDescriptor()
+
+
+ /**
+ * A [BodyTypeDescriptor] of the specific given type (or empty if type is null).
+ */
+ fun typeOf(type: SchemaType?) = type?.let { SchemaBodyTypeDescriptor(it) } ?: EmptyBodyTypeDescriptor()
+
+
+ /**
+ * A [BodyTypeDescriptor] of the specific given generic type.
+ */
+ inline fun typeOf() = SchemaBodyTypeDescriptor(getSchemaType())
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ fun oneOf(vararg type: KClass<*>) = OneOfBodyTypeDescriptor(type.toList().map { typeOf(it.asSchemaType()) })
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ @JvmName("oneOfClass")
+ fun oneOf(types: Collection>) = OneOfBodyTypeDescriptor(types.map { typeOf(it.asSchemaType()) })
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ fun oneOf(vararg type: SchemaType) = OneOfBodyTypeDescriptor(type.map { typeOf(it) })
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ @JvmName("oneOfType")
+ fun oneOf(types: Collection) = OneOfBodyTypeDescriptor(types.map { typeOf(it) })
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ fun oneOf(vararg type: BodyTypeDescriptor) = OneOfBodyTypeDescriptor(type.toList())
+
+
+ /**
+ * Type can be any one of the given types.
+ */
+ @JvmName("oneOfDescriptor")
+ fun oneOf(types: Collection) = OneOfBodyTypeDescriptor(types.toList())
+
+
+ /**
+ * Type is an array of the specific given type.
+ */
+ fun multipleOf(type: KClass<*>) = CollectionBodyTypeDescriptor(typeOf(type.asSchemaType()))
+
+
+ /**
+ * Type is an array of the specific given type.
+ */
+ fun multipleOf(type: SchemaType) = CollectionBodyTypeDescriptor(typeOf(type))
+
+
+ /**
+ * Type is an array of the given type.
+ */
+ fun multipleOf(type: BodyTypeDescriptor) = CollectionBodyTypeDescriptor(type)
+
+
+ /**
+ * A [BodyTypeDescriptor] of the specific given custom schema.
+ */
+ fun custom(customSchemaId: String) = CustomRefBodyTypeDescriptor(customSchemaId)
+
+
+ /**
+ * An empty type.
+ */
+ fun empty() = EmptyBodyTypeDescriptor()
+ }
+
+}
+
+
+/**
+ * Describes an empty type
+ */
+class EmptyBodyTypeDescriptor : BodyTypeDescriptor
+
+
+/**
+ * Describes a specific type/schema
+ */
+class SchemaBodyTypeDescriptor(val schemaType: SchemaType) : BodyTypeDescriptor
+
+
+/**
+ * Describes any one of the given types
+ */
+class OneOfBodyTypeDescriptor(val elements: List) : BodyTypeDescriptor
+
+
+/**
+ * Describes an array of the given type
+ */
+class CollectionBodyTypeDescriptor(val schemaType: BodyTypeDescriptor) : BodyTypeDescriptor
+
+
+/**
+ * Describes the custom schema/type with the given id
+ */
+class CustomRefBodyTypeDescriptor(val customSchemaId: String) : BodyTypeDescriptor
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemaRef.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemaRef.kt
index ef0c7fd2..417bef81 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemaRef.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemaRef.kt
@@ -1,13 +1,14 @@
package io.github.smiley4.ktorswaggerui.dsl
-sealed class CustomSchemaRef(
- val schemaId: String
+@Deprecated(
+ "Use BodyTypeDescriptor instead",
+ ReplaceWith("BodyTypeDescriptor.custom(schemaId)")
)
+fun obj(schemaId: String) = BodyTypeDescriptor.custom(schemaId)
-class CustomObjectSchemaRef(schemaId: String) : CustomSchemaRef(schemaId)
-class CustomArraySchemaRef(schemaId: String) : CustomSchemaRef(schemaId)
-
-fun obj(schemaId: String) = CustomObjectSchemaRef(schemaId)
-
-fun array(schemaId: String) = CustomArraySchemaRef(schemaId)
+@Deprecated(
+ "Use BodyTypeDescriptor instead",
+ ReplaceWith("BodyTypeDescriptor.multipleOf(BodyTypeDescriptor.custom(schemaId))")
+)
+fun array(schemaId: String) = BodyTypeDescriptor.multipleOf(BodyTypeDescriptor.custom(schemaId))
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemas.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemas.kt
index 6aa07e64..11f5e8fe 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemas.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/CustomSchemas.kt
@@ -1,5 +1,9 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.BaseCustomSchema
+import io.github.smiley4.ktorswaggerui.data.CustomJsonSchema
+import io.github.smiley4.ktorswaggerui.data.CustomOpenApiSchema
+import io.github.smiley4.ktorswaggerui.data.RemoteSchema
import io.swagger.v3.oas.models.media.Schema
@OpenApiDslMarker
@@ -43,10 +47,3 @@ class CustomSchemas {
}
-sealed class BaseCustomSchema
-
-class CustomJsonSchema(val provider: () -> String) : BaseCustomSchema()
-
-class CustomOpenApiSchema(val provider: () -> Schema) : BaseCustomSchema()
-
-class RemoteSchema(val url: String) : BaseCustomSchema()
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/EncodingConfig.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/EncodingConfig.kt
index 9acf46b6..1714a227 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/EncodingConfig.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/EncodingConfig.kt
@@ -1,15 +1,7 @@
package io.github.smiley4.ktorswaggerui.dsl
-import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
-import com.github.victools.jsonschema.generator.Option
-import com.github.victools.jsonschema.generator.OptionPreset
-import com.github.victools.jsonschema.generator.SchemaGenerator
-import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder
-import com.github.victools.jsonschema.generator.SchemaVersion
-import com.github.victools.jsonschema.module.jackson.JacksonModule
-import com.github.victools.jsonschema.module.swagger2.Swagger2Module
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaTypeAttributeOverride
-import kotlin.reflect.jvm.javaType
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeDefault
+import io.github.smiley4.ktorswaggerui.data.EncodingData
typealias ExampleEncoder = (type: SchemaType?, example: Any) -> String?
@@ -29,9 +21,7 @@ class EncodingConfig {
exampleEncoder = encoder
}
- private var exampleEncoder: ExampleEncoder = defaultExampleEncoder()
-
- fun getExampleEncoder() = exampleEncoder
+ private var exampleEncoder: ExampleEncoder = EncodingData.DEFAULT.exampleEncoder
/**
@@ -42,85 +32,19 @@ class EncodingConfig {
schemaEncoder = encoder
}
- private var schemaEncoder: SchemaEncoder = defaultSchemaEncoder()
-
- fun getSchemaEncoder() = schemaEncoder
+ private var schemaEncoder: SchemaEncoder = EncodingData.DEFAULT.schemaEncoder
/**
* the name of the field (if it exists) in the json-schema containing schema-definitions.
*/
- var schemaDefinitionsField = "\$defs"
-
- companion object {
-
- /**
- * The default jackson object mapper used for encoding examples to json.
- */
- var DEFAULT_EXAMPLE_OBJECT_MAPPER = jacksonObjectMapper()
-
-
- /**
- * The default [SchemaGenerator] used to encode types to json-schema.
- * See https://victools.github.io/jsonschema-generator/#generator-options for more information.
- */
- var DEFAULT_SCHEMA_GENERATOR = SchemaGenerator(schemaGeneratorConfigBuilder().build())
-
-
- /**
- * The default [ExampleEncoder]
- */
- fun defaultExampleEncoder(): ExampleEncoder {
- return { _, value -> encodeExample(value) }
- }
-
+ var schemaDefinitionsField = EncodingData.DEFAULT.schemaDefsField
- /**
- * encode the given value to a json string
- */
- fun encodeExample(value: Any?): String {
- return if (value is String) {
- value
- } else {
- DEFAULT_EXAMPLE_OBJECT_MAPPER.writeValueAsString(value)
- }
- }
-
- /**
- * The default [SchemaEncoder]
- */
- fun defaultSchemaEncoder(): SchemaEncoder {
- return { type -> encodeSchema(type) }
- }
-
-
- /**
- * encode the given type to a json-schema
- */
- fun encodeSchema(type: SchemaType): String {
- return DEFAULT_SCHEMA_GENERATOR.generateSchema(type.javaType).toPrettyString()
- }
-
-
- /**
- * The default [SchemaGeneratorConfigBuilder]
- */
- fun schemaGeneratorConfigBuilder(): SchemaGeneratorConfigBuilder =
- SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09, OptionPreset.PLAIN_JSON)
- .with(JacksonModule())
- .with(Swagger2Module())
- .with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
- .with(Option.ALLOF_CLEANUP_AT_THE_END)
- .with(Option.MAP_VALUES_AS_ADDITIONAL_PROPERTIES)
- .with(Option.DEFINITIONS_FOR_ALL_OBJECTS)
- .without(Option.INLINE_ALL_SCHEMAS)
- .also {
- it.forTypesInGeneral()
- .withTypeAttributeOverride(SchemaTypeAttributeOverride())
- }
-
-
- }
+ fun build(base: EncodingData) = EncodingData(
+ exampleEncoder = mergeDefault(base.exampleEncoder, exampleEncoder, EncodingData.DEFAULT.exampleEncoder),
+ schemaEncoder = mergeDefault(base.schemaEncoder, schemaEncoder, EncodingData.DEFAULT.schemaEncoder),
+ schemaDefsField = mergeDefault(base.schemaDefsField, schemaDefinitionsField, EncodingData.DEFAULT.schemaDefsField),
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiContact.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiContact.kt
index 06403d20..7ab26b64 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiContact.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiContact.kt
@@ -1,5 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.ContactData
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+
/**
* Contact information for the exposed API.
*/
@@ -9,18 +12,25 @@ class OpenApiContact {
/**
* The identifying name of the contact person/organization.
*/
- var name: String? = null
+ var name: String? = ContactData.DEFAULT.name
/**
* The URL pointing to the contact information. MUST be in the format of a URL.
*/
- var url: String? = null
+ var url: String? = ContactData.DEFAULT.url
/**
* The email address of the contact person/organization. MUST be in the format of an email address.
*/
- var email: String? = null
+ var email: String? = ContactData.DEFAULT.email
+
+
+ fun build(base: ContactData) = ContactData(
+ name = merge(base.name, name),
+ url = merge(base.url, url),
+ email = merge(base.email, email)
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiExternalDocs.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiExternalDocs.kt
index c1ce30dd..7fd85bce 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiExternalDocs.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiExternalDocs.kt
@@ -1,5 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.DataUtils
+import io.github.smiley4.ktorswaggerui.data.ExternalDocsData
+
/**
* An object representing external documentation.
*/
@@ -10,8 +13,15 @@ class OpenApiExternalDocs {
*/
var description: String? = null
+
/**
* A URL to the external documentation
*/
var url: String = "/"
+
+ fun build(base: ExternalDocsData) = ExternalDocsData(
+ url = DataUtils.mergeDefault(base.url, url, ExternalDocsData.DEFAULT.url),
+ description = DataUtils.merge(base.description, description)
+ )
+
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiInfo.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiInfo.kt
index 9671e43f..98efa891 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiInfo.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiInfo.kt
@@ -1,5 +1,11 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.ContactData
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeDefault
+import io.github.smiley4.ktorswaggerui.data.InfoData
+import io.github.smiley4.ktorswaggerui.data.LicenseData
+
@OpenApiDslMarker
class OpenApiInfo {
@@ -26,9 +32,9 @@ class OpenApiInfo {
*/
var termsOfService: String? = null
-
private var contact: OpenApiContact? = null
+
/**
* The contact information for the exposed API.
*/
@@ -36,11 +42,10 @@ class OpenApiInfo {
contact = OpenApiContact().apply(block)
}
- fun getContact() = contact
-
private var license: OpenApiLicense? = null
+
/**
* The license information for the exposed API.
*/
@@ -48,6 +53,15 @@ class OpenApiInfo {
license = OpenApiLicense().apply(block)
}
- fun getLicense() = license
+ fun build(base: InfoData): InfoData {
+ return InfoData(
+ title = mergeDefault(base.title, this.title, InfoData.DEFAULT.title),
+ version = merge(base.version, this.version),
+ description = merge(base.description, this.description),
+ termsOfService = merge(base.termsOfService, this.termsOfService),
+ contact = contact?.build(base.contact ?: ContactData.DEFAULT) ?: base.contact,
+ license = license?.build(base.license ?: LicenseData.DEFAULT) ?: base.license
+ )
+ }
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiLicense.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiLicense.kt
index b15cace3..5faf8d9f 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiLicense.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiLicense.kt
@@ -1,5 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.DataUtils
+import io.github.smiley4.ktorswaggerui.data.LicenseData
+
/**
* License information for the exposed API.
*/
@@ -9,12 +12,17 @@ class OpenApiLicense {
/**
* The license name used for the API
*/
- var name: String = "?"
+ var name: String? = LicenseData.DEFAULT.name
/**
* A URL to the license used for the API. MUST be in the format of a URL.
*/
- var url: String? = null
+ var url: String? = LicenseData.DEFAULT.url
+
+ fun build(base: LicenseData) = LicenseData(
+ name = DataUtils.merge(base.name, name),
+ url = DataUtils.merge(base.url, url),
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartBody.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartBody.kt
index 67f2568b..fd5a61d2 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartBody.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartBody.kt
@@ -18,7 +18,7 @@ class OpenApiMultipartBody : OpenApiBaseBody() {
/**
* One part of a multipart-body
*/
- fun part(name: String, type: SchemaType, block: OpenApiMultipartPart.() -> Unit) {
+ fun part(name: String, type: BodyTypeDescriptor, block: OpenApiMultipartPart.() -> Unit) {
parts.add(OpenApiMultipartPart(name, type).apply(block))
}
@@ -26,41 +26,38 @@ class OpenApiMultipartBody : OpenApiBaseBody() {
/**
* One part of a multipart-body
*/
- fun part(name: String, type: KClass<*>) = part(name, type.asSchemaType()) {}
+ fun part(name: String, type: BodyTypeDescriptor) = part(name, type) {}
/**
* One part of a multipart-body
*/
- inline fun part(name: String) = part(name, getSchemaType()) {}
+ fun part(name: String, type: SchemaType, block: OpenApiMultipartPart.() -> Unit) = part(name, BodyTypeDescriptor.typeOf(type), block)
/**
* One part of a multipart-body
*/
- inline fun part(name: String, noinline block: OpenApiMultipartPart.() -> Unit) = part(name, getSchemaType(), block)
+ fun part(name: String, type: KClass<*>) = part(name, type.asSchemaType()) {}
/**
* One part of a multipart-body
*/
- fun part(name: String, customSchema: CustomSchemaRef, block: OpenApiMultipartPart.() -> Unit) {
- parts.add(OpenApiMultipartPart(name, null).apply(block).apply {
- this.customSchema = customSchema
- })
- }
+ inline fun part(name: String) = part(name, getSchemaType()) {}
/**
* One part of a multipart-body
*/
- fun part(name: String, customSchema: CustomSchemaRef) = part(name, customSchema) {}
+ inline fun part(name: String, noinline block: OpenApiMultipartPart.() -> Unit) = part(name, getSchemaType(), block)
/**
* One part of a multipart-body
*/
- fun part(name: String, customSchemaId: String, block: OpenApiMultipartPart.() -> Unit) = part(name, obj(customSchemaId), block)
+ fun part(name: String, customSchemaId: String, block: OpenApiMultipartPart.() -> Unit) =
+ part(name, BodyTypeDescriptor.custom(customSchemaId), block)
/**
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartPart.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartPart.kt
index f06e8088..60ae1f7d 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartPart.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiMultipartPart.kt
@@ -14,15 +14,9 @@ class OpenApiMultipartPart(
*/
val name: String,
- val type: SchemaType?
+ val type: BodyTypeDescriptor
) {
- /**
- * reference to a custom schema (alternative to 'type')
- */
- var customSchema: CustomSchemaRef? = null
-
-
/**
* Set a specific content type for this part
*/
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRequest.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRequest.kt
index 0ef7ad49..0f851e7b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRequest.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRequest.kt
@@ -110,23 +110,21 @@ class OpenApiRequest {
/**
- * The request body applicable for this operation
+ * The body returned with this request
*/
- fun body(type: SchemaType?, block: OpenApiSimpleBody.() -> Unit) {
- body = OpenApiSimpleBody(type).apply(block)
+ fun body(typeDescriptor: BodyTypeDescriptor, block: OpenApiSimpleBody.() -> Unit) {
+ body = OpenApiSimpleBody(typeDescriptor).apply(block)
}
/**
- * The request body applicable for this operation
+ * The body returned with this request
*/
- fun body(type: KClass<*>, block: OpenApiSimpleBody.() -> Unit) = body(type.asSchemaType(), block)
-
+ fun body(typeDescriptor: BodyTypeDescriptor) = body(typeDescriptor) {}
/**
* The request body applicable for this operation
*/
- @JvmName("bodyGenericType")
- inline fun body(noinline block: OpenApiSimpleBody.() -> Unit) = body(getSchemaType(), block)
+ fun body(type: SchemaType?, block: OpenApiSimpleBody.() -> Unit) = body(BodyTypeDescriptor.typeOf(type), block)
/**
@@ -138,41 +136,38 @@ class OpenApiRequest {
/**
* The request body applicable for this operation
*/
- inline fun body() = body(getSchemaType()) {}
+ fun body(type: KClass<*>, block: OpenApiSimpleBody.() -> Unit) = body(type.asSchemaType(), block)
/**
* The request body applicable for this operation
*/
- fun body(block: OpenApiSimpleBody.() -> Unit) = body(null, block)
+ @JvmName("bodyGenericType")
+ inline fun body(noinline block: OpenApiSimpleBody.() -> Unit) = body(getSchemaType(), block)
/**
- * The body returned with this request
+ * The request body applicable for this operation
*/
- fun body(customSchema: CustomSchemaRef, block: OpenApiSimpleBody.() -> Unit) {
- body = OpenApiSimpleBody(null).apply(block).apply {
- this.customSchema = customSchema
- }
- }
+ inline fun body() = body(getSchemaType()) {}
/**
- * The body returned with this request
+ * The request body applicable for this operation
*/
- fun body(customSchema: CustomSchemaRef) = body(customSchema) {}
+ fun body(block: OpenApiSimpleBody.() -> Unit) = body(BodyTypeDescriptor.empty(), block)
/**
* The body returned with this request
*/
- fun body(customSchemaId: String, block: OpenApiSimpleBody.() -> Unit) = body(obj(customSchemaId), block)
+ fun body(customSchemaId: String) = body(customSchemaId) {}
/**
* The body returned with this request
*/
- fun body(customSchemaId: String) = body(customSchemaId) {}
+ fun body(customSchemaId: String, block: OpenApiSimpleBody.() -> Unit) = body(BodyTypeDescriptor.custom(customSchemaId), block)
/**
@@ -190,5 +185,4 @@ class OpenApiRequest {
this.body = body
}
-
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiResponse.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiResponse.kt
index 77b244a4..4d9c4b92 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiResponse.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiResponse.kt
@@ -61,7 +61,7 @@ class OpenApiResponse(val statusCode: String) {
/**
* The body returned with this response
*/
- fun body(type: SchemaType?, block: OpenApiSimpleBody.() -> Unit) {
+ fun body(type: BodyTypeDescriptor, block: OpenApiSimpleBody.() -> Unit) {
body = OpenApiSimpleBody(type).apply(block)
}
@@ -69,54 +69,49 @@ class OpenApiResponse(val statusCode: String) {
/**
* The body returned with this response
*/
- fun body(type: KClass<*>, block: OpenApiSimpleBody.() -> Unit) = body(type.asSchemaType(), block)
+ fun body(type: BodyTypeDescriptor) = body(type) {}
/**
* The body returned with this response
*/
- @JvmName("bodyGenericType")
- inline fun body(noinline block: OpenApiSimpleBody.() -> Unit) = body(getSchemaType(), block)
+ fun body(type: SchemaType?, block: OpenApiSimpleBody.() -> Unit) = body(BodyTypeDescriptor.typeOf(type), block)
/**
* The body returned with this response
*/
- fun body(type: KClass<*>) = body(type) {}
+ fun body(type: KClass<*>, block: OpenApiSimpleBody.() -> Unit) = body(type.asSchemaType(), block)
/**
* The body returned with this response
*/
- inline fun body() = body(getSchemaType()) {}
+ @JvmName("bodyGenericType")
+ inline fun body(noinline block: OpenApiSimpleBody.() -> Unit) = body(getSchemaType(), block)
/**
* The body returned with this response
*/
- fun body(block: OpenApiSimpleBody.() -> Unit) = body(null, block)
+ fun body(type: KClass<*>) = body(type) {}
/**
* The body returned with this response
*/
- fun body(customSchema: CustomSchemaRef, block: OpenApiSimpleBody.() -> Unit) {
- body = OpenApiSimpleBody(null).apply(block).apply {
- this.customSchema = customSchema
- }
- }
+ inline fun body() = body(getSchemaType()) {}
/**
* The body returned with this response
*/
- fun body(customSchema: CustomSchemaRef) = body(customSchema) {}
-
+ fun body(block: OpenApiSimpleBody.() -> Unit) = body(null, block)
/**
* The body returned with this response
*/
- fun body(customSchemaId: String, block: OpenApiSimpleBody.() -> Unit) = body(obj(customSchemaId), block)
+ fun body(customSchemaId: String, block: OpenApiSimpleBody.() -> Unit) = body(BodyTypeDescriptor.custom(customSchemaId), block)
/**
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRoute.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRoute.kt
index e3781dfb..68dc0dbc 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRoute.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiRoute.kt
@@ -3,6 +3,11 @@ package io.github.smiley4.ktorswaggerui.dsl
@OpenApiDslMarker
class OpenApiRoute {
+ /**
+ * the id of the openapi-spec this route belongs to. 'Null' to use default spec.
+ */
+ var specId: String? = null
+
/**
* A list of tags for API documentation control. Tags can be used for logical grouping of operations by resources or any other qualifier
*/
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSecurityScheme.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSecurityScheme.kt
index 9754230c..4a6e265d 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSecurityScheme.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSecurityScheme.kt
@@ -1,35 +1,11 @@
package io.github.smiley4.ktorswaggerui.dsl
-import io.swagger.v3.oas.models.security.SecurityScheme
-
-
-enum class AuthType(val swaggerType: SecurityScheme.Type) {
- API_KEY(SecurityScheme.Type.APIKEY),
- HTTP(SecurityScheme.Type.HTTP),
- OAUTH2(SecurityScheme.Type.OAUTH2),
- OPENID_CONNECT(SecurityScheme.Type.OPENIDCONNECT),
- MUTUAL_TLS(SecurityScheme.Type.MUTUALTLS)
-}
-
-enum class AuthKeyLocation(val swaggerType: SecurityScheme.In) {
- QUERY(SecurityScheme.In.QUERY),
- HEADER(SecurityScheme.In.HEADER),
- COOKIE(SecurityScheme.In.COOKIE)
-}
-
-
-// https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
-enum class AuthScheme(val swaggerType: String) {
- BASIC("Basic"),
- BEARER("Bearer"),
- DIGEST("Digest"),
- HOBA("HOBA"),
- MUTUAL("Mutual"),
- OAUTH("OAuth"),
- SCRAM_SHA_1("SCRAM-SHA-1"),
- SCRAM_SHA_256("SCRAM-SHA-256"),
- VAPID("vapid")
-}
+import io.github.smiley4.ktorswaggerui.data.AuthKeyLocation
+import io.github.smiley4.ktorswaggerui.data.AuthScheme
+import io.github.smiley4.ktorswaggerui.data.AuthType
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowsData
+import io.github.smiley4.ktorswaggerui.data.SecuritySchemeData
/**
@@ -83,9 +59,6 @@ class OpenApiSecurityScheme(
}
- fun getFlows() = flows
-
-
/**
* OpenId Connect URL to discover OAuth2 configuration values.
* Required for type [AuthType.OPENID_CONNECT]
@@ -98,4 +71,15 @@ class OpenApiSecurityScheme(
*/
var description: String? = null
+
+ fun build(base: SecuritySchemeData) = SecuritySchemeData(
+ name = name,
+ type = merge(base.type, type),
+ location = merge(base.location, location),
+ scheme = merge(base.scheme, scheme),
+ bearerFormat = merge(base.bearerFormat, bearerFormat),
+ flows = flows?.build(base.flows ?: OpenIdOAuthFlowsData.DEFAULT) ?: base.flows,
+ openIdConnectUrl = merge(base.openIdConnectUrl, openIdConnectUrl),
+ description = merge(base.description, description),
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiServer.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiServer.kt
index c8914097..74367b63 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiServer.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiServer.kt
@@ -1,5 +1,9 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeDefault
+import io.github.smiley4.ktorswaggerui.data.ServerData
+
/**
* An object representing a Server.
*/
@@ -10,12 +14,17 @@ class OpenApiServer {
* A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to
* the location where the OpenAPI document is being served
*/
- var url: String = "/"
+ var url: String = ServerData.DEFAULT.url
/**
* An optional string describing the host designated by the URL
*/
- var description: String? = null
+ var description: String? = ServerData.DEFAULT.description
+
+ fun build(base: ServerData) = ServerData(
+ url = mergeDefault(base.url, url, ServerData.DEFAULT.url),
+ description = merge(base.description, description)
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSimpleBody.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSimpleBody.kt
index 4ea77e51..cd2de62a 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSimpleBody.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiSimpleBody.kt
@@ -9,15 +9,9 @@ class OpenApiSimpleBody(
/**
* The type defining the schema used for the body.
*/
- val type: SchemaType?,
+ val type: BodyTypeDescriptor,
) : OpenApiBaseBody() {
- /**
- * reference to a custom schema (alternative to 'type')
- */
- var customSchema: CustomSchemaRef? = null
-
-
/**
* Examples for this body
*/
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiTag.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiTag.kt
index 0fcf5f6b..2d81c93b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiTag.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenApiTag.kt
@@ -1,5 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.TagData
+
/**
* Adds metadata to a single tag.
*/
@@ -28,4 +31,12 @@ class OpenApiTag(
*/
var externalDocUrl: String? = null
+
+ fun build(base: TagData) = TagData(
+ name = name,
+ description = merge(base.description, description),
+ externalDocDescription = merge(base.externalDocDescription, externalDocDescription),
+ externalDocUrl = merge(base.externalDocUrl, externalDocUrl)
+ )
+
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlow.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlow.kt
index 2e31e198..55ececa5 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlow.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlow.kt
@@ -1,4 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowData
+
/**
* Configuration details for a supported OAuth Flow
*/
@@ -28,4 +32,12 @@ class OpenIdOAuthFlow {
*/
var scopes: Map? = null
+
+ fun build(base: OpenIdOAuthFlowData) = OpenIdOAuthFlowData(
+ authorizationUrl = merge(base.authorizationUrl, authorizationUrl),
+ tokenUrl = merge(base.tokenUrl, tokenUrl),
+ refreshUrl = merge(base.refreshUrl, refreshUrl),
+ scopes = merge(base.scopes, scopes),
+ )
+
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlows.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlows.kt
index 123a4417..b13bb47b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlows.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/OpenIdOAuthFlows.kt
@@ -1,5 +1,8 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowData
+import io.github.smiley4.ktorswaggerui.data.OpenIdOAuthFlowsData
+
/**
* An object containing configuration information for the oauth flow types supported
*/
@@ -17,9 +20,6 @@ class OpenIdOAuthFlows {
}
- fun getImplicit() = implicit
-
-
private var password: OpenIdOAuthFlow? = null
@@ -31,9 +31,6 @@ class OpenIdOAuthFlows {
}
- fun getPassword() = password
-
-
private var clientCredentials: OpenIdOAuthFlow? = null
@@ -45,9 +42,6 @@ class OpenIdOAuthFlows {
}
- fun getClientCredentials() = clientCredentials
-
-
private var authorizationCode: OpenIdOAuthFlow? = null
@@ -59,6 +53,11 @@ class OpenIdOAuthFlows {
}
- fun getAuthorizationCode() = authorizationCode
+ fun build(base: OpenIdOAuthFlowsData) = OpenIdOAuthFlowsData(
+ implicit = implicit?.build(base.implicit ?: OpenIdOAuthFlowData.DEFAULT) ?: base.implicit,
+ password = password?.build(base.password ?: OpenIdOAuthFlowData.DEFAULT) ?: base.password,
+ clientCredentials = clientCredentials?.build(base.clientCredentials ?: OpenIdOAuthFlowData.DEFAULT) ?: base.clientCredentials,
+ authorizationCode = authorizationCode?.build(base.authorizationCode ?: OpenIdOAuthFlowData.DEFAULT) ?: base.authorizationCode,
+ )
}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/PluginConfigDsl.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/PluginConfigDsl.kt
new file mode 100644
index 00000000..b89ef3e4
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/PluginConfigDsl.kt
@@ -0,0 +1,211 @@
+package io.github.smiley4.ktorswaggerui.dsl
+
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeBoolean
+import io.github.smiley4.ktorswaggerui.data.PathFilter
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.data.SecuritySchemeData
+import io.github.smiley4.ktorswaggerui.data.ServerData
+import io.github.smiley4.ktorswaggerui.data.SpecAssigner
+import io.github.smiley4.ktorswaggerui.data.TagData
+import io.github.smiley4.ktorswaggerui.data.TagGenerator
+import io.ktor.http.HttpStatusCode
+import io.ktor.server.routing.RouteSelector
+import kotlin.reflect.KClass
+
+/**
+ * Main-Configuration of the "SwaggerUI"-Plugin
+ */
+@OpenApiDslMarker
+class PluginConfigDsl {
+
+ companion object {
+ const val DEFAULT_SPEC_ID = "api"
+ }
+
+
+ private val specConfigs = mutableMapOf()
+
+ fun spec(specId: String, block: PluginConfigDsl.() -> Unit) {
+ specConfigs[specId] = PluginConfigDsl().apply(block)
+ }
+
+
+ /**
+ * Default response to automatically add to each protected route for the "Unauthorized"-Response-Code.
+ * Generated response can be overwritten with custom response.
+ */
+ fun defaultUnauthorizedResponse(block: OpenApiResponse.() -> Unit) {
+ defaultUnauthorizedResponse = OpenApiResponse(HttpStatusCode.Unauthorized.value.toString()).apply(block)
+ }
+
+ private var defaultUnauthorizedResponse: OpenApiResponse? = PluginConfigData.DEFAULT.defaultUnauthorizedResponse
+
+
+ /**
+ * The name of the security scheme to use for the protected paths
+ */
+ var defaultSecuritySchemeName: String? = null
+
+
+ /**
+ * The names of the security schemes available for use for the protected paths
+ */
+ var defaultSecuritySchemeNames: Collection? = PluginConfigData.DEFAULT.defaultSecuritySchemeNames
+
+
+ /**
+ * Automatically add tags to the route with the given url.
+ * The returned (non-null) tags will be added to the tags specified in the route-specific documentation.
+ */
+ fun generateTags(generator: TagGenerator) {
+ tagGenerator = generator
+ }
+
+ private var tagGenerator: TagGenerator? = PluginConfigData.DEFAULT.tagGenerator
+
+
+ /**
+ * Assigns routes without an [io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute.specId] to a specified openapi-spec.
+ */
+ var specAssigner: SpecAssigner? = PluginConfigData.DEFAULT.specAssigner
+
+
+ /**
+ * Filter to apply to all routes. Return 'false' for routes to not include them in the OpenApi-Spec and Swagger-UI.
+ * The url of the paths are already split at '/'.
+ */
+ var pathFilter: PathFilter? = PluginConfigData.DEFAULT.pathFilter
+
+
+ /**
+ * Swagger-UI configuration
+ */
+ fun swagger(block: SwaggerUIDsl.() -> Unit) {
+ swaggerUI = SwaggerUIDsl().apply(block)
+ }
+
+ private var swaggerUI = SwaggerUIDsl()
+
+
+ /**
+ * OpenAPI info configuration - provides metadata about the API
+ */
+ fun info(block: OpenApiInfo.() -> Unit) {
+ info = OpenApiInfo().apply(block)
+ }
+
+ private var info = OpenApiInfo()
+
+
+ /**
+ * OpenAPI server configuration - an array of servers, which provide connectivity information to a target server
+ */
+ fun server(block: OpenApiServer.() -> Unit) {
+ servers.add(OpenApiServer().apply(block))
+ }
+
+ private val servers = mutableListOf()
+
+
+ /**
+ * OpenAPI external docs configuration - link and description of an external documentation
+ */
+ fun externalDocs(block: OpenApiExternalDocs.() -> Unit) {
+ externalDocs = OpenApiExternalDocs().apply(block)
+ }
+
+ private var externalDocs = OpenApiExternalDocs()
+
+
+ /**
+ * Defines security schemes that can be used by operations
+ */
+ fun securityScheme(name: String, block: OpenApiSecurityScheme.() -> Unit) {
+ securitySchemes.add(OpenApiSecurityScheme(name).apply(block))
+ }
+
+ private val securitySchemes = mutableListOf()
+
+
+ /**
+ * Tags used by the specification with additional metadata. Not all tags that are used must be declared
+ */
+ fun tag(name: String, block: OpenApiTag.() -> Unit) {
+ tags.add(OpenApiTag(name).apply(block))
+ }
+
+ private val tags = mutableListOf()
+
+
+ /**
+ * Custom schemas to reference via [io.github.smiley4.ktorswaggerui.dsl.CustomSchemaRef]
+ */
+ fun customSchemas(block: CustomSchemas.() -> Unit) {
+ this.customSchemas = CustomSchemas().apply(block)
+ }
+
+ private var customSchemas = CustomSchemas()
+
+
+ /**
+ * customize the behaviour of different encoders (examples, schemas, ...)
+ */
+ fun encoding(block: EncodingConfig.() -> Unit) {
+ block(encodingConfig)
+ }
+
+ val encodingConfig: EncodingConfig = EncodingConfig()
+
+
+ /**
+ * List of all [RouteSelector] types in that should be ignored in the resulting url of any route.
+ */
+ var ignoredRouteSelectors: Set> = PluginConfigData.DEFAULT.ignoredRouteSelectors
+
+
+ internal fun build(base: PluginConfigData): PluginConfigData {
+ return PluginConfigData(
+ defaultUnauthorizedResponse = merge(base.defaultUnauthorizedResponse, defaultUnauthorizedResponse),
+ defaultSecuritySchemeNames = buildSet {
+ addAll(base.defaultSecuritySchemeNames)
+ defaultSecuritySchemeNames?.also { addAll(it) }
+ defaultSecuritySchemeName?.also { add(it) }
+ },
+ tagGenerator = merge(base.tagGenerator, tagGenerator) ?: PluginConfigData.DEFAULT.tagGenerator,
+ specAssigner = merge(base.specAssigner, specAssigner) ?: PluginConfigData.DEFAULT.specAssigner,
+ pathFilter = merge(base.pathFilter, pathFilter) ?: PluginConfigData.DEFAULT.pathFilter,
+ ignoredRouteSelectors = buildSet {
+ addAll(base.ignoredRouteSelectors)
+ addAll(ignoredRouteSelectors)
+ },
+ swaggerUI = swaggerUI.build(base.swaggerUI),
+ info = info.build(base.info),
+ servers = buildList {
+ addAll(base.servers)
+ addAll(servers.map { it.build(ServerData.DEFAULT) })
+ },
+ externalDocs = externalDocs.build(base.externalDocs),
+ securitySchemes = buildList {
+ addAll(base.securitySchemes)
+ addAll(securitySchemes.map { it.build(SecuritySchemeData.DEFAULT) })
+ },
+ tags = buildList {
+ addAll(base.tags)
+ addAll(tags.map { it.build(TagData.DEFAULT) })
+ },
+ customSchemas = buildMap {
+ putAll(base.customSchemas)
+ putAll(customSchemas.getSchemas())
+ },
+ includeAllCustomSchemas = mergeBoolean(base.includeAllCustomSchemas, customSchemas.includeAll),
+ encoding = encodingConfig.build(base.encoding),
+ specConfigs = mutableMapOf()
+ ).also {
+ specConfigs.forEach { (specId, config) ->
+ it.specConfigs[specId] = config.build(it)
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUIDsl.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUIDsl.kt
index 16544351..0144409b 100644
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUIDsl.kt
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUIDsl.kt
@@ -1,27 +1,37 @@
package io.github.smiley4.ktorswaggerui.dsl
+import io.github.smiley4.ktorswaggerui.data.DataUtils.merge
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeBoolean
+import io.github.smiley4.ktorswaggerui.data.DataUtils.mergeDefault
+import io.github.smiley4.ktorswaggerui.data.SwaggerUIData
+
+
@OpenApiDslMarker
class SwaggerUIDsl {
/**
* Whether to forward the root-url to the swagger-url
*/
- var forwardRoot: Boolean = false
+ var forwardRoot: Boolean = SwaggerUIData.DEFAULT.forwardRoot
+
/**
* the url to the swagger-ui
*/
- var swaggerUrl: String = "swagger-ui"
+ var swaggerUrl: String = SwaggerUIData.DEFAULT.swaggerUrl
+
/**
* the path under which the KTOR app gets deployed. can be useful if reverse proxy is in use.
*/
- var rootHostPath: String = ""
+ var rootHostPath: String = SwaggerUIData.DEFAULT.rootHostPath
+
/**
* The name of the authentication to use for the swagger routes. Null to not protect the swagger-ui.
*/
- var authentication: String? = null
+ var authentication: String? = SwaggerUIData.DEFAULT.authentication
+
/**
* Swagger UI can attempt to validate specs against swagger.io's online validator.
@@ -30,7 +40,7 @@ class SwaggerUIDsl {
* Validation is disabled when the url of the api-spec-file contains localhost.
* (see https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md#network)
*/
- private var validatorUrl: String? = null
+ private var validatorUrl: String? = SwaggerUIData.DEFAULT.validatorUrl
fun disableSpecValidator() {
validatorUrl = null
@@ -46,50 +56,44 @@ class SwaggerUIDsl {
fun getSpecValidatorUrl() = validatorUrl
+
/**
* Whether to show the operation-id of endpoints in the list
*/
- var displayOperationId = false
+ var displayOperationId = SwaggerUIData.DEFAULT.displayOperationId
+
/**
* Whether the top bar will show an edit box that you can use to filter the tagged operations.
*/
- var showTagFilterInput = false
+ var showTagFilterInput = SwaggerUIData.DEFAULT.showTagFilterInput
- /**
- * Apply a sort to the operation list of each API
- */
- var sort = SwaggerUiSort.NONE
/**
- * Syntax coloring theme to use
+ * Apply a sort to the operation list of each API
*/
- var syntaxHighlight = SwaggerUiSyntaxHighlight.AGATE
-
-}
+ var sort = SwaggerUIData.DEFAULT.sort
-enum class SwaggerUiSort(val value: String) {
- /**
- * The order returned by the server unchanged
- */
- NONE("undefined"),
/**
- * sort by paths alphanumerically
+ * Syntax coloring theme to use
*/
- ALPHANUMERICALLY("alpha"),
+ var syntaxHighlight = SwaggerUIData.DEFAULT.syntaxHighlight
+
+
+ internal fun build(base: SwaggerUIData): SwaggerUIData {
+ return SwaggerUIData(
+ forwardRoot = mergeBoolean(base.forwardRoot, this.forwardRoot),
+ swaggerUrl = mergeDefault(base.swaggerUrl, this.swaggerUrl, SwaggerUIData.DEFAULT.swaggerUrl),
+ rootHostPath = mergeDefault(base.rootHostPath, this.rootHostPath, SwaggerUIData.DEFAULT.rootHostPath),
+ authentication = merge(base.authentication, this.authentication),
+ validatorUrl = merge(base.validatorUrl, this.validatorUrl),
+ displayOperationId = mergeBoolean(base.displayOperationId, this.displayOperationId),
+ showTagFilterInput = mergeBoolean(base.showTagFilterInput, this.showTagFilterInput),
+ sort = mergeDefault(base.sort, this.sort, SwaggerUIData.DEFAULT.sort),
+ syntaxHighlight = mergeDefault(base.syntaxHighlight, this.syntaxHighlight, SwaggerUIData.DEFAULT.syntaxHighlight)
+ )
+ }
- /**
- * sort by HTTP method
- */
- HTTP_METHOD("method")
}
-enum class SwaggerUiSyntaxHighlight(val value: String) {
- AGATE("agate"),
- ARTA("arta"),
- MONOKAI("monokai"),
- NORD("nord"),
- OBSIDIAN("obsidian"),
- TOMORROW_NIGHT("tomorrow-night")
-}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ControllerUtils.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ControllerUtils.kt
new file mode 100644
index 00000000..bb990937
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ControllerUtils.kt
@@ -0,0 +1,18 @@
+package io.github.smiley4.ktorswaggerui.routing
+
+import io.ktor.server.config.ApplicationConfig
+
+object ControllerUtils {
+
+ fun getRootPath(appConfig: ApplicationConfig): String {
+ return appConfig.propertyOrNull("ktor.deployment.rootPath")?.getString()?.let { "/${dropSlashes(it)}" } ?: ""
+ }
+
+ fun dropSlashes(str: String): String {
+ var value = str
+ value = if (value.startsWith("/")) value.substring(1) else value
+ value = if (value.endsWith("/")) value.substring(0, value.length - 1) else value
+ return value
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ForwardRouteController.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ForwardRouteController.kt
new file mode 100644
index 00000000..bcaa16b0
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ForwardRouteController.kt
@@ -0,0 +1,35 @@
+package io.github.smiley4.ktorswaggerui.routing
+
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.ktor.server.application.Application
+import io.ktor.server.application.call
+import io.ktor.server.config.ApplicationConfig
+import io.ktor.server.response.respondRedirect
+import io.ktor.server.routing.get
+import io.ktor.server.routing.routing
+
+class ForwardRouteController(
+ private val appConfig: ApplicationConfig,
+ private val swaggerUiConfig: PluginConfigData,
+) {
+
+ fun setup(app: Application) {
+ app.routing {
+ get {
+ call.respondRedirect("${getRootUrl()}/index.html")
+ }
+ }
+ }
+
+ private fun getRootUrl(): String {
+ return "/" + listOf(
+ ControllerUtils.getRootPath(appConfig),
+ swaggerUiConfig.swaggerUI.rootHostPath,
+ swaggerUiConfig.swaggerUI.swaggerUrl,
+ )
+ .filter { it.isNotBlank() }
+ .map { ControllerUtils.dropSlashes(it) }
+ .joinToString("/")
+ }
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ResourceContent.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ResourceContent.kt
new file mode 100644
index 00000000..9523187a
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/ResourceContent.kt
@@ -0,0 +1,32 @@
+package io.github.smiley4.ktorswaggerui.routing
+
+import io.ktor.http.ContentType
+import io.ktor.http.content.OutgoingContent
+import io.ktor.http.withCharset
+import java.net.URL
+
+class ResourceContent(private val resource: URL) : OutgoingContent.ByteArrayContent() {
+
+ private val contentTypes = mapOf(
+ "html" to ContentType.Text.Html,
+ "css" to ContentType.Text.CSS,
+ "js" to ContentType.Application.JavaScript,
+ "json" to ContentType.Application.Json.withCharset(Charsets.UTF_8),
+ "png" to ContentType.Image.PNG
+ )
+
+ private val bytes by lazy { resource.readBytes() }
+
+ override val contentType: ContentType? by lazy {
+ val extension = resource.file.substring(resource.file.lastIndexOf('.') + 1)
+ contentTypes[extension] ?: ContentType.Text.Html
+ }
+
+ override val contentLength: Long? by lazy {
+ bytes.size.toLong()
+ }
+
+ override fun bytes(): ByteArray = bytes
+
+ override fun toString() = "ResourceContent \"$resource\""
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/SwaggerController.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/SwaggerController.kt
new file mode 100644
index 00000000..9e991f9e
--- /dev/null
+++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/routing/SwaggerController.kt
@@ -0,0 +1,126 @@
+package io.github.smiley4.ktorswaggerui.routing
+
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.data.SwaggerUiSort
+import io.ktor.http.ContentType
+import io.ktor.http.HttpStatusCode
+import io.ktor.server.application.Application
+import io.ktor.server.application.ApplicationCall
+import io.ktor.server.application.call
+import io.ktor.server.auth.authenticate
+import io.ktor.server.config.ApplicationConfig
+import io.ktor.server.request.uri
+import io.ktor.server.response.respond
+import io.ktor.server.response.respondRedirect
+import io.ktor.server.response.respondText
+import io.ktor.server.routing.Route
+import io.ktor.server.routing.get
+import io.ktor.server.routing.route
+import io.ktor.server.routing.routing
+
+class SwaggerController(
+ private val appConfig: ApplicationConfig,
+ private val pluginConfig: PluginConfigData,
+ private val swaggerWebjarVersion: String,
+ private val specName: String?,
+ private val jsonSpec: String,
+) {
+
+ companion object {
+ const val DEFAULT_SPEC_NAME: String = "api"
+ }
+
+ fun setup(app: Application) {
+ app.routing {
+ if (pluginConfig.swaggerUI.authentication == null) {
+ setup()
+ } else {
+ authenticate(pluginConfig.swaggerUI.authentication) {
+ setup()
+ }
+ }
+ }
+ }
+
+ private fun Route.setup() {
+ route(getSubUrl()) {
+ get {
+ call.respondRedirect("${call.request.uri}/index.html")
+ }
+ get("{filename}") {
+ serveStaticResource(call.parameters["filename"]!!, call)
+ }
+ get("swagger-initializer.js") {
+ serveSwaggerInitializer(call)
+ }
+ get("${specName ?: DEFAULT_SPEC_NAME}.json") {
+ serveOpenApiSpec(call)
+ }
+ }
+ }
+
+ private suspend fun serveSwaggerInitializer(call: ApplicationCall) {
+ val swaggerUiConfig = pluginConfig.swaggerUI
+ // see https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md for reference
+ val propValidatorUrl = swaggerUiConfig.validatorUrl?.let { "validatorUrl: \"$it\"" } ?: "validatorUrl: false"
+ val propDisplayOperationId = "displayOperationId: ${swaggerUiConfig.displayOperationId}"
+ val propFilter = "filter: ${swaggerUiConfig.showTagFilterInput}"
+ val propSort = "operationsSorter: " +
+ if (swaggerUiConfig.sort == SwaggerUiSort.NONE) "undefined"
+ else "\"${swaggerUiConfig.sort.value}\""
+ val propSyntaxHighlight = "syntaxHighlight: { theme: \"${swaggerUiConfig.syntaxHighlight.value}\" }"
+ val content = """
+ window.onload = function() {
+ window.ui = SwaggerUIBundle({
+ url: "${getRootUrl(appConfig)}/${specName ?: DEFAULT_SPEC_NAME}.json",
+ dom_id: '#swagger-ui',
+ deepLinking: true,
+ presets: [
+ SwaggerUIBundle.presets.apis,
+ SwaggerUIStandalonePreset
+ ],
+ plugins: [
+ SwaggerUIBundle.plugins.DownloadUrl
+ ],
+ layout: "StandaloneLayout",
+ $propValidatorUrl,
+ $propDisplayOperationId,
+ $propFilter,
+ $propSort,
+ $propSyntaxHighlight
+ });
+ };
+ """.trimIndent()
+ call.respondText(ContentType.Application.JavaScript, HttpStatusCode.OK) { content }
+ }
+
+ private suspend fun serveOpenApiSpec(call: ApplicationCall) {
+ call.respondText(ContentType.Application.Json, HttpStatusCode.OK) { jsonSpec }
+ }
+
+ private suspend fun serveStaticResource(filename: String, call: ApplicationCall) {
+ val resource = this::class.java.getResource("/META-INF/resources/webjars/swagger-ui/$swaggerWebjarVersion/$filename")
+ if (resource != null) {
+ call.respond(ResourceContent(resource))
+ } else {
+ call.respond(HttpStatusCode.NotFound, "$filename could not be found")
+ }
+ }
+
+ private fun getRootUrl(appConfig: ApplicationConfig): String {
+ return "${ControllerUtils.getRootPath(appConfig)}${getSubUrl()}"
+ }
+
+ private fun getSubUrl(): String {
+ return "/" + listOf(
+ pluginConfig.swaggerUI.rootHostPath,
+ pluginConfig.swaggerUI.swaggerUrl,
+ specName
+ )
+ .filter { !it.isNullOrBlank() }
+ .map { ControllerUtils.dropSlashes(it!!) }
+ .joinToString("/")
+ }
+
+
+}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OAuthFlowsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OAuthFlowsBuilder.kt
deleted file mode 100644
index 1fc2ddfe..00000000
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OAuthFlowsBuilder.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
-
-import io.github.smiley4.ktorswaggerui.dsl.OpenIdOAuthFlow
-import io.github.smiley4.ktorswaggerui.dsl.OpenIdOAuthFlows
-import io.swagger.v3.oas.models.security.OAuthFlow
-import io.swagger.v3.oas.models.security.OAuthFlows
-import io.swagger.v3.oas.models.security.Scopes
-
-class OAuthFlowsBuilder {
-
- fun build(flows: OpenIdOAuthFlows): OAuthFlows {
- return OAuthFlows().apply {
- implicit = flows.getImplicit()?.let { build(it) }
- password = flows.getPassword()?.let { build(it) }
- clientCredentials = flows.getClientCredentials()?.let { build(it) }
- authorizationCode = flows.getAuthorizationCode()?.let { build(it) }
- }
- }
-
- private fun build(flow: OpenIdOAuthFlow): OAuthFlow {
- return OAuthFlow().apply {
- authorizationUrl = flow.authorizationUrl
- tokenUrl = flow.tokenUrl
- refreshUrl = flow.refreshUrl
- scopes = flow.scopes?.let { buildScopes(it) }
- }
- }
-
- private fun buildScopes(scopes: Map): Scopes {
- return Scopes().apply {
- scopes.forEach { (k, v) -> addString(k, v) }
- }
- }
-
-}
diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationTagsBuilder.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationTagsBuilder.kt
deleted file mode 100644
index 30fa43e6..00000000
--- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/spec/openapi/OperationTagsBuilder.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.github.smiley4.ktorswaggerui.spec.openapi
-
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-
-class OperationTagsBuilder(
- private val config: SwaggerUIPluginConfig
-) {
-
- fun build(route: RouteMeta): List {
- return mutableSetOf().also { tags ->
- tags.addAll(getGeneratedTags(route))
- tags.addAll(getRouteTags(route))
- }.filterNotNull()
- }
-
- private fun getRouteTags(route: RouteMeta) = route.documentation.tags
-
- private fun getGeneratedTags(route: RouteMeta) = config.getTagGenerator()(route.path.split("/").filter { it.isNotEmpty() })
-
-}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/AuthExample.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/AuthExample.kt
index 09943daa..79410f64 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/AuthExample.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/AuthExample.kt
@@ -1,8 +1,8 @@
package io.github.smiley4.ktorswaggerui.examples
import io.github.smiley4.ktorswaggerui.SwaggerUI
-import io.github.smiley4.ktorswaggerui.dsl.AuthScheme
-import io.github.smiley4.ktorswaggerui.dsl.AuthType
+import io.github.smiley4.ktorswaggerui.data.AuthScheme
+import io.github.smiley4.ktorswaggerui.data.AuthType
import io.github.smiley4.ktorswaggerui.dsl.get
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompletePluginConfigExample.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompletePluginConfigExample.kt
index 539b90d6..70f21ba3 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompletePluginConfigExample.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CompletePluginConfigExample.kt
@@ -3,11 +3,12 @@ package io.github.smiley4.ktorswaggerui.examples
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.github.victools.jsonschema.generator.SchemaGenerator
import io.github.smiley4.ktorswaggerui.SwaggerUI
-import io.github.smiley4.ktorswaggerui.dsl.AuthScheme
-import io.github.smiley4.ktorswaggerui.dsl.AuthType
+import io.github.smiley4.ktorswaggerui.data.AuthScheme
+import io.github.smiley4.ktorswaggerui.data.AuthType
+import io.github.smiley4.ktorswaggerui.data.EncodingData
+import io.github.smiley4.ktorswaggerui.data.SwaggerUiSort
+import io.github.smiley4.ktorswaggerui.data.SwaggerUiSyntaxHighlight
import io.github.smiley4.ktorswaggerui.dsl.EncodingConfig
-import io.github.smiley4.ktorswaggerui.dsl.SwaggerUiSort
-import io.github.smiley4.ktorswaggerui.dsl.SwaggerUiSyntaxHighlight
import io.ktor.server.application.Application
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer
@@ -98,7 +99,7 @@ private fun Application.myModule() {
}
encoding {
schemaEncoder { type ->
- SchemaGenerator(EncodingConfig.schemaGeneratorConfigBuilder().build())
+ SchemaGenerator(EncodingData.schemaGeneratorConfigBuilder().build())
.generateSchema(type.javaType)
.toPrettyString()
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomJsonSchemaExample.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomSchemaExample.kt
similarity index 73%
rename from src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomJsonSchemaExample.kt
rename to src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomSchemaExample.kt
index 23b3ffdc..73b71f7e 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomJsonSchemaExample.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/CustomSchemaExample.kt
@@ -1,9 +1,11 @@
package io.github.smiley4.ktorswaggerui.examples
import io.github.smiley4.ktorswaggerui.SwaggerUI
-import io.github.smiley4.ktorswaggerui.dsl.array
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.custom
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.multipleOf
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.oneOf
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.typeOf
import io.github.smiley4.ktorswaggerui.dsl.get
-import io.github.smiley4.ktorswaggerui.dsl.obj
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
@@ -34,6 +36,20 @@ private fun Application.myModule() {
val someNumber: Long
)
+ data class Rectangle(
+ val width: Int,
+ val height: Int
+ )
+
+ data class Circle(
+ val radius: Int
+ )
+
+ data class Point(
+ val x: Int,
+ val y: Int
+ )
+
install(SwaggerUI) {
// don't show the test-routes providing json-schemas
pathFilter = { _, url -> url.firstOrNull() != "schema" }
@@ -64,12 +80,12 @@ private fun Application.myModule() {
get("something", {
request {
// body referencing the custom schema with id 'myRequestData'
- body(obj("myRequestData"))
+ body("myRequestData")
}
response {
HttpStatusCode.OK to {
// body referencing the custom schema with id 'myResponseData'
- body(obj("myResponseData"))
+ body("myResponseData")
}
}
}) {
@@ -80,12 +96,12 @@ private fun Application.myModule() {
get("something/many", {
request {
// body referencing the custom schema with id 'myRequestData'
- body(array("myRequestData"))
+ body(multipleOf(custom("myRequestData")))
}
response {
HttpStatusCode.OK to {
// body referencing the custom schema with id 'myResponseData'
- body(array("myResponseData"))
+ body(multipleOf(custom("myResponseData")))
}
}
}) {
@@ -93,6 +109,23 @@ private fun Application.myModule() {
call.respond(HttpStatusCode.OK, MyResponseData(text, 42))
}
+ get("oneof/shapes", {
+ request {
+ // body allowing a mixed list of rectangles, circles and points
+ body(
+ multipleOf(
+ oneOf(
+ typeOf(Rectangle::class),
+ typeOf(Circle::class),
+ typeOf(Point::class),
+ )
+ )
+ )
+ }
+ }) {
+ call.respond(HttpStatusCode.OK, Unit)
+ }
+
// (external) endpoint providing a json-schema
get("schema/myResponseData") {
call.respondText(
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/MultipleSpecsExample.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/MultipleSpecsExample.kt
new file mode 100644
index 00000000..9b712d48
--- /dev/null
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/examples/MultipleSpecsExample.kt
@@ -0,0 +1,102 @@
+package io.github.smiley4.ktorswaggerui.examples
+
+import io.github.smiley4.ktorswaggerui.SwaggerUI
+import io.github.smiley4.ktorswaggerui.dsl.get
+import io.github.smiley4.ktorswaggerui.dsl.route
+import io.ktor.server.application.Application
+import io.ktor.server.application.call
+import io.ktor.server.application.install
+import io.ktor.server.auth.Authentication
+import io.ktor.server.auth.UserIdPrincipal
+import io.ktor.server.auth.basic
+import io.ktor.server.engine.embeddedServer
+import io.ktor.server.netty.Netty
+import io.ktor.server.response.respondText
+import io.ktor.server.routing.routing
+
+/**
+ * An example showcasing multiple openapi-specs in a single application
+ * - localhost:8080/swagger-ui/v1/index.html
+ * * /v1/hello
+ * - localhost:8080/swagger-ui/v2/index.html
+ * * /v2/hello
+ * * /hi
+ */
+fun main() {
+ embeddedServer(Netty, port = 8080, host = "localhost", module = Application::myModule).start(wait = true)
+}
+
+private fun Application.myModule() {
+
+ install(Authentication) {
+ basic("auth-swagger") {
+ realm = "Access to the Swagger UI"
+ validate { credentials ->
+ if (credentials.name == "user" && credentials.password == "pass") {
+ UserIdPrincipal(credentials.name)
+ } else {
+ null
+ }
+ }
+ }
+ }
+
+ install(SwaggerUI) {
+ // general configuration
+ info {
+ title = "Example API"
+ }
+ specAssigner = { _, _ -> "v2" } // assign all unassigned routes to spec "v2" (here e.g. '/hi')
+
+ // configuration specific for spec "v1"
+ spec("v1") {
+ info {
+ version = "1.0"
+ }
+ }
+
+ // configuration specific for spec "v2"
+ spec("v2") {
+ info {
+ version = "2.0"
+ }
+ swagger {
+ authentication = "auth-swagger"
+ }
+ }
+ }
+
+
+ routing {
+
+ // version 1.0 routes
+ route("v1", {
+ specId = "v1" // assign all sub-routes to spec "v1"
+ }) {
+ get("hello", {
+ description = "Simple version 1 'Hello World'-Route"
+ }) {
+ call.respondText("Hello World!")
+ }
+ }
+
+ // version 2.0 routes
+ route("v2", {
+ specId = "v2" // assign all sub-routes to spec "v2"
+ }) {
+ get("hello", {
+ description = "Simple version 2 'Hello World'-Route"
+ }) {
+ call.respondText("Improved Hello World!")
+ }
+ }
+
+ // other routes
+ get("hi", {
+ description = "Alternative version of 'Hello World'-Route"
+ }) {
+ call.respondText("Alternative Hello World!")
+ }
+
+ }
+}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/ApplicationTests.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/ApplicationTests.kt
index 43197f74..e9c7fe79 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/ApplicationTests.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/ApplicationTests.kt
@@ -1,9 +1,10 @@
package io.github.smiley4.ktorswaggerui.tests
import io.github.smiley4.ktorswaggerui.SwaggerUI
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.dsl.get
import io.kotest.matchers.shouldBe
+import io.kotest.matchers.string.shouldContain
import io.kotest.matchers.string.shouldNotBeEmpty
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
@@ -24,141 +25,443 @@ import kotlin.test.Test
class ApplicationTests {
- private fun ApplicationTestBuilder.setupTestApplication(pluginConfig: SwaggerUIPluginConfig.() -> Unit) {
- application {
- install(Authentication) {
- basic("my-auth") {
- validate { credentials ->
- if (credentials.name == "user" && credentials.password == "pass") {
- UserIdPrincipal(credentials.name)
- } else {
- null
- }
- }
- }
- }
- install(SwaggerUI) { pluginConfig() }
- routing {
- get("hello", {
- description = "Simple 'Hello World'- Route"
- response {
- HttpStatusCode.OK to {
- description = "Successful Response"
- }
- }
- }) {
- call.respondText("Hello Test")
- }
- }
+ @Test
+ fun minimal() = swaggerUITestApplication {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/swagger-ui/api.json\""
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
}
}
@Test
- fun testDefaultSwaggerUi() = testApplication {
- setupTestApplication {}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/").status shouldBe HttpStatusCode.NotFound
- client.get("/swagger-ui").let {
+ fun customRootHost() = swaggerUITestApplication({
+ swagger {
+ rootHostPath = "my-root"
+ }
+ }) {
+ get("hello").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Text.Html
- it.bodyAsText().shouldNotBeEmpty()
+ it.body shouldBe "Hello Test"
}
- client.get("/swagger-ui/api.json").let {
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("my-root/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("my-root/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("my-root/swagger-ui/swagger-initializer.js").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/my-root/swagger-ui/api.json\""
+
+ }
+ get("my-root/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
}
}
+
@Test
- fun testSwaggerUiForwardRoot() = testApplication {
- setupTestApplication {
- swagger {
- forwardRoot = true
- }
+ fun forwardRoot() = swaggerUITestApplication({
+ swagger {
+ forwardRoot = true
+ }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/").let {
+ get("/swagger-ui").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Text.Html
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
}
- client.get("/swagger-ui").let {
+ get("/swagger-ui/index.html").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Text.Html
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
}
- client.get("/swagger-ui/api.json").let {
+ get("/swagger-ui/swagger-initializer.js").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/swagger-ui/api.json\""
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
}
}
+
@Test
- fun testSwaggerUiProtected() = testApplication {
- setupTestApplication {
- swagger {
- authentication = "my-auth"
- }
+ fun forwardRootWithCustomSwaggerUrl() = swaggerUITestApplication({
+ swagger {
+ forwardRoot = true
+ swaggerUrl = "test-swagger"
+ }
+ }) {
+ get("/").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/test-swagger").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/test-swagger/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/").status shouldBe HttpStatusCode.NotFound
- client.get("/swagger-ui").status shouldBe HttpStatusCode.Unauthorized
- client.get("/swagger-ui/api.json").status shouldBe HttpStatusCode.Unauthorized
}
+
@Test
- fun testSwaggerUiProtectedAndForwardRoot() = testApplication {
- setupTestApplication {
- swagger {
- authentication = "my-auth"
- forwardRoot = true
- }
+ fun protectedSwaggerUI() = swaggerUITestApplication({
+ swagger {
+ authentication = "my-auth"
+ }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/").status shouldBe HttpStatusCode.Unauthorized
- client.get("/swagger-ui").status shouldBe HttpStatusCode.Unauthorized
- client.get("/swagger-ui/api.json").status shouldBe HttpStatusCode.Unauthorized
}
@Test
- fun testSwaggerUiCustomRoute() = testApplication {
- setupTestApplication {
- swagger {
- swaggerUrl = "test-swagger"
- }
+ fun forwardRootAndProtectedSwaggerUI() = swaggerUITestApplication({
+ swagger {
+ authentication = "my-auth"
+ forwardRoot = true
+ }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ }
+
+
+ @Test
+ fun customSwaggerUrl() = swaggerUITestApplication({
+ swagger {
+ swaggerUrl = "test-swagger"
+ }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.NotFound
}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/swagger-ui").status shouldBe HttpStatusCode.NotFound
- client.get("/swagger-ui/api.json").status shouldBe HttpStatusCode.NotFound
- client.get("/test-swagger").let {
+ get("/swagger-ui/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/test-swagger").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/test-swagger/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/test-swagger/swagger-initializer.js").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Text.Html
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/test-swagger/api.json\""
+
}
- client.get("/test-swagger/api.json").let {
+ get("/test-swagger/api.json").also {
it.status shouldBe HttpStatusCode.OK
- it.contentType() shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
- it.bodyAsText().shouldNotBeEmpty()
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
}
}
+
@Test
- fun testSwaggerUiCustomRouteProtected() = testApplication {
- setupTestApplication {
+ fun customSwaggerUrlAndProtected() = swaggerUITestApplication({
+ swagger {
+ authentication = "my-auth"
+ swaggerUrl = "test-swagger"
+ }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/index.html").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/api.json").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/test-swagger").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/test-swagger/index.html").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/test-swagger/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/test-swagger/api.json").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ }
+
+
+ @Test
+ fun multipleSwaggerUI() = swaggerUITestApplication({
+ specAssigner = { _, tags -> tags.firstOrNull() ?: "other" }
+ }) {
+ get("hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.body shouldBe "Hello Test"
+ }
+ get("/").also {
+ it.status shouldBe HttpStatusCode.NotFound
+ }
+ get("/swagger-ui/hello").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/hello/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/hello/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/swagger-ui/hello/hello.json\""
+ }
+ get("/swagger-ui/hello/hello.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/world").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/world/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/world/swagger-initializer.js").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.JavaScript.withCharset(Charsets.UTF_8)
+ it.body shouldContain "url: \"/swagger-ui/world/world.json\""
+ }
+ get("/swagger-ui/world/world.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
+ }
+ }
+
+
+ @Test
+ fun multipleSwaggerUIWithDifferentAuthConfig() = swaggerUITestApplication({
+ specAssigner = { _, tags -> tags.firstOrNull() ?: "other" }
+ spec("hello") {
+ swagger {
+ authentication = null
+ }
+ }
+ spec("world") {
swagger {
authentication = "my-auth"
- swaggerUrl = "test-swagger"
}
}
- client.get("/hello").bodyAsText() shouldBe "Hello Test"
- client.get("/swagger-ui").status shouldBe HttpStatusCode.NotFound
- client.get("/swagger-ui/api.json").status shouldBe HttpStatusCode.NotFound
- client.get("/test-swagger").status shouldBe HttpStatusCode.Unauthorized
- client.get("/test-swagger/api.json").status shouldBe HttpStatusCode.Unauthorized
+ }) {
+ get("/swagger-ui/hello/index.html").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Text.Html
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/hello/hello.json").also {
+ it.status shouldBe HttpStatusCode.OK
+ it.contentType shouldBe ContentType.Application.Json.withCharset(Charsets.UTF_8)
+ it.body.shouldNotBeEmpty()
+ }
+ get("/swagger-ui/world/index.html").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ get("/swagger-ui/world/world.json").also {
+ it.status shouldBe HttpStatusCode.Unauthorized
+ }
+ }
+
+
+ private fun swaggerUITestApplication(block: suspend ApplicationTestBuilder.() -> Unit) {
+ swaggerUITestApplication({}, block)
+ }
+
+ private fun swaggerUITestApplication(pluginConfig: PluginConfigDsl.() -> Unit, block: suspend ApplicationTestBuilder.() -> Unit) {
+ testApplication {
+ application {
+ install(Authentication) {
+ basic("my-auth") {
+ validate { credentials ->
+ if (credentials.name == "user" && credentials.password == "pass") {
+ UserIdPrincipal(credentials.name)
+ } else {
+ null
+ }
+ }
+ }
+ }
+ install(SwaggerUI, pluginConfig)
+ routing {
+ get("hello", {
+ tags = listOf("hello")
+ description = "Simple 'Hello World'- Route"
+ response {
+ HttpStatusCode.OK to {
+ description = "Successful Response"
+ }
+ }
+ }) {
+ call.respondText("Hello Test")
+ }
+ get("world", {
+ tags = listOf("world")
+ description = "Another simple 'Hello World'- Route"
+ response {
+ HttpStatusCode.OK to {
+ description = "Successful Response"
+ }
+ }
+ }) {
+ call.respondText("Hello World")
+ }
+ }
+ Thread.sleep(500)
+ }
+ block()
+ }
+ }
+
+ private suspend fun ApplicationTestBuilder.get(path: String): GetResult {
+ return client.get(path)
+ .let {
+ GetResult(
+ path = path,
+ status = it.status,
+ contentType = it.contentType(),
+ body = it.bodyAsText()
+ )
+ }
+ .also { it.print() }
+ }
+
+ private data class GetResult(
+ val path: String,
+ val status: HttpStatusCode,
+ val contentType: ContentType?,
+ val body: String,
+ )
+
+ private fun GetResult.print() {
+ println("GET ${this.path} => ${this.status} (${this.contentType}): ${this.body}")
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/example/ExampleTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/example/ExampleTest.kt
index bcb23358..7dae2e56 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/example/ExampleTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/example/ExampleTest.kt
@@ -1,13 +1,14 @@
package io.github.smiley4.ktorswaggerui.tests.example
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRequestParameter
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSimpleBody
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExampleBuilder
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.shouldNotBe
@@ -166,15 +167,15 @@ class ExampleTest : StringSpec({
}
- private val defaultPluginConfig = SwaggerUIPluginConfig()
+ private val defaultPluginConfig = PluginConfigDsl()
private fun exampleContext(
routes: List,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): ExampleContext {
return ExampleContextBuilder(
exampleBuilder = ExampleBuilder(
- config = pluginConfig
+ config = pluginConfig.build(PluginConfigData.DEFAULT)
)
).build(routes.toList())
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ExternalDocsBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ExternalDocsBuilderTest.kt
index 22138528..d49ab313 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ExternalDocsBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ExternalDocsBuilderTest.kt
@@ -1,7 +1,8 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
+import io.github.smiley4.ktorswaggerui.data.ExternalDocsData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiExternalDocs
-import io.github.smiley4.ktorswaggerui.spec.openapi.ExternalDocumentationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExternalDocumentationBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.swagger.v3.oas.models.ExternalDocumentation
@@ -30,7 +31,7 @@ class ExternalDocsBuilderTest : StringSpec({
companion object {
private fun buildExternalDocsObject(builder: OpenApiExternalDocs.() -> Unit): ExternalDocumentation {
- return ExternalDocumentationBuilder().build(OpenApiExternalDocs().apply(builder))
+ return ExternalDocumentationBuilder().build(OpenApiExternalDocs().apply(builder).build(ExternalDocsData.DEFAULT))
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/InfoBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/InfoBuilderTest.kt
index 96a6ccd3..51475ef2 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/InfoBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/InfoBuilderTest.kt
@@ -1,9 +1,10 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
+import io.github.smiley4.ktorswaggerui.data.InfoData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiInfo
-import io.github.smiley4.ktorswaggerui.spec.openapi.ContactBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.InfoBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.LicenseBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ContactBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.InfoBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.LicenseBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
@@ -72,7 +73,7 @@ class InfoBuilderTest : StringSpec({
return InfoBuilder(
contactBuilder = ContactBuilder(),
licenseBuilder = LicenseBuilder()
- ).build(OpenApiInfo().apply(builder))
+ ).build(OpenApiInfo().apply(builder).build(InfoData.DEFAULT))
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OpenApiBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OpenApiBuilderTest.kt
index b63df8ed..f682ce89 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OpenApiBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OpenApiBuilderTest.kt
@@ -1,15 +1,16 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
import com.fasterxml.jackson.databind.ObjectMapper
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.*
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.*
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.collections.shouldHaveSize
@@ -36,7 +37,7 @@ class OpenApiBuilderTest : StringSpec({
}
"multiple servers" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.server {
url = "http://localhost:8080"
description = "Development Server"
@@ -56,7 +57,7 @@ class OpenApiBuilderTest : StringSpec({
}
"multiple tags" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.tag("tag-1") {
description = "first test tag"
}
@@ -77,33 +78,35 @@ class OpenApiBuilderTest : StringSpec({
companion object {
- private val defaultPluginConfig = SwaggerUIPluginConfig()
+ private val defaultPluginConfig = PluginConfigDsl()
- private fun schemaContext(routes: List, pluginConfig: SwaggerUIPluginConfig): SchemaContext {
+ private fun schemaContext(routes: List, pluginConfig: PluginConfigDsl): SchemaContext {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return SchemaContextBuilder(
- config = pluginConfig,
+ config =pluginConfigData,
schemaBuilder = SchemaBuilder(
- definitionsField = pluginConfig.encodingConfig.schemaDefinitionsField,
- schemaEncoder = pluginConfig.encodingConfig.getSchemaEncoder(),
+ definitionsField = pluginConfigData.encoding.schemaDefsField,
+ schemaEncoder = pluginConfigData.encoding.schemaEncoder,
ObjectMapper(),
TypeOverwrites.get()
)
).build(routes)
}
- private fun exampleContext(routes: List, pluginConfig: SwaggerUIPluginConfig): ExampleContext {
+ private fun exampleContext(routes: List, pluginConfig: PluginConfigDsl): ExampleContext {
return ExampleContextBuilder(
exampleBuilder = ExampleBuilder(
- config = pluginConfig
+ config = pluginConfig.build(PluginConfigData.DEFAULT)
)
).build(routes.toList())
}
- private fun buildOpenApiObject(routes: List, pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig): OpenAPI {
+ private fun buildOpenApiObject(routes: List, pluginConfig: PluginConfigDsl = defaultPluginConfig): OpenAPI {
val schemaContext = schemaContext(routes, pluginConfig)
val exampleContext = exampleContext(routes, pluginConfig)
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return OpenApiBuilder(
- config = pluginConfig,
+ config = pluginConfigData,
schemaContext = schemaContext,
exampleContext = exampleContext,
infoBuilder = InfoBuilder(
@@ -118,7 +121,7 @@ class OpenApiBuilderTest : StringSpec({
pathsBuilder = PathsBuilder(
pathBuilder = PathBuilder(
operationBuilder = OperationBuilder(
- operationTagsBuilder = OperationTagsBuilder(pluginConfig),
+ operationTagsBuilder = OperationTagsBuilder(pluginConfigData),
parameterBuilder = ParameterBuilder(
schemaContext = schemaContext,
exampleContext = exampleContext
@@ -139,14 +142,14 @@ class OpenApiBuilderTest : StringSpec({
headerBuilder = HeaderBuilder(schemaContext)
)
),
- config = pluginConfig
+ config = pluginConfigData
),
- securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfig),
+ securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfigData),
)
)
),
componentsBuilder = ComponentsBuilder(
- config = pluginConfig,
+ config = pluginConfigData,
securitySchemesBuilder = SecuritySchemesBuilder(
oAuthFlowsBuilder = OAuthFlowsBuilder()
)
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OperationBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OperationBuilderTest.kt
index d230cabc..39184ed1 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OperationBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/OperationBuilderTest.kt
@@ -1,26 +1,28 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
import com.fasterxml.jackson.databind.ObjectMapper
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
-import io.github.smiley4.ktorswaggerui.dsl.obj
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ContentBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.HeaderBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.OperationBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.OperationTagsBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ParameterBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.RequestBodyBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ResponseBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ResponsesBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.SecurityRequirementsBuilder
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ContentBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExampleBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.HeaderBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationTagsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ParameterBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.RequestBodyBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponseBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponsesBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.SecurityRequirementsBuilder
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.custom
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
@@ -95,7 +97,7 @@ class OperationBuilderTest : StringSpec({
}
"operation with auto-generated tags" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.generateTags { url -> listOf(url.firstOrNull()) }
}
val routeA = RouteMeta(
@@ -682,7 +684,7 @@ class OperationBuilderTest : StringSpec({
}
"automatic unauthorized response for protected route" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.defaultUnauthorizedResponse {
description = "Default unauthorized Response"
}
@@ -716,7 +718,7 @@ class OperationBuilderTest : StringSpec({
}
"automatic unauthorized response for unprotected route" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.defaultUnauthorizedResponse {
description = "Default unauthorized Response"
}
@@ -803,7 +805,7 @@ class OperationBuilderTest : StringSpec({
}
"custom body schema" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
openApi("myCustomSchema") {
Schema().also { schema ->
@@ -822,7 +824,7 @@ class OperationBuilderTest : StringSpec({
method = HttpMethod.Get,
documentation = OpenApiRoute().also { route ->
route.request {
- body(obj("myCustomSchema"))
+ body(custom("myCustomSchema"))
}
},
protected = false
@@ -860,7 +862,7 @@ class OperationBuilderTest : StringSpec({
}
"custom multipart-body schema" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
openApi("myCustomSchema") {
Schema().also { schema ->
@@ -881,7 +883,7 @@ class OperationBuilderTest : StringSpec({
route.request {
multipartBody {
mediaType(ContentType.MultiPart.FormData)
- part("customData", obj("myCustomSchema"))
+ part("customData", custom("myCustomSchema"))
}
}
},
@@ -927,17 +929,18 @@ class OperationBuilderTest : StringSpec({
val number: Int
)
- private val defaultPluginConfig = SwaggerUIPluginConfig()
+ private val defaultPluginConfig = PluginConfigDsl()
private fun schemaContext(
routes: List,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): SchemaContext {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return SchemaContextBuilder(
- config = pluginConfig,
+ config = pluginConfigData,
schemaBuilder = SchemaBuilder(
- definitionsField = pluginConfig.encodingConfig.schemaDefinitionsField,
- schemaEncoder = pluginConfig.encodingConfig.getSchemaEncoder(),
+ definitionsField = pluginConfigData.encoding.schemaDefsField,
+ schemaEncoder = pluginConfigData.encoding.schemaEncoder,
ObjectMapper(),
TypeOverwrites.get()
)
@@ -946,11 +949,11 @@ class OperationBuilderTest : StringSpec({
private fun exampleContext(
routes: List,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): ExampleContext {
return ExampleContextBuilder(
exampleBuilder = ExampleBuilder(
- config = pluginConfig
+ config = pluginConfig.build(PluginConfigData.DEFAULT)
)
).build(routes.toList())
}
@@ -960,10 +963,11 @@ class OperationBuilderTest : StringSpec({
route: RouteMeta,
schemaContext: SchemaContext,
exampleContext: ExampleContext,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): Operation {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return OperationBuilder(
- operationTagsBuilder = OperationTagsBuilder(pluginConfig),
+ operationTagsBuilder = OperationTagsBuilder(pluginConfigData),
parameterBuilder = ParameterBuilder(
schemaContext = schemaContext,
exampleContext = exampleContext
@@ -984,9 +988,9 @@ class OperationBuilderTest : StringSpec({
headerBuilder = HeaderBuilder(schemaContext)
)
),
- config = pluginConfig
+ config = pluginConfigData
),
- securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfig),
+ securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfigData),
).build(route)
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/PathsBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/PathsBuilderTest.kt
index ac6efdb0..29f69a44 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/PathsBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/PathsBuilderTest.kt
@@ -1,27 +1,28 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
import com.fasterxml.jackson.databind.ObjectMapper
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
-import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ContentBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.HeaderBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.OperationBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.OperationTagsBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ParameterBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.PathBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.PathsBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.RequestBodyBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ResponseBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.ResponsesBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.SecurityRequirementsBuilder
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext
+import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ContentBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ExampleBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.HeaderBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OperationTagsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ParameterBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.PathBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.PathsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.RequestBodyBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponseBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ResponsesBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.SecurityRequirementsBuilder
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.maps.shouldHaveSize
@@ -88,24 +89,25 @@ class PathsBuilderTest : StringSpec({
protected = false
)
- private val defaultPluginConfig = SwaggerUIPluginConfig()
+ private val defaultPluginConfig = PluginConfigDsl()
- private fun schemaContext(routes: List, pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig): SchemaContext {
+ private fun schemaContext(routes: List, pluginConfig: PluginConfigDsl = defaultPluginConfig): SchemaContext {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return SchemaContextBuilder(
- config = pluginConfig,
+ config = pluginConfigData,
schemaBuilder = SchemaBuilder(
- definitionsField = pluginConfig.encodingConfig.schemaDefinitionsField,
- schemaEncoder = pluginConfig.encodingConfig.getSchemaEncoder(),
+ definitionsField = pluginConfigData.encoding.schemaDefsField,
+ schemaEncoder = pluginConfigData.encoding.schemaEncoder,
ObjectMapper(),
TypeOverwrites.get()
)
).build(routes)
}
- private fun exampleContext(routes: List, pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig): ExampleContext {
+ private fun exampleContext(routes: List, pluginConfig: PluginConfigDsl = defaultPluginConfig): ExampleContext {
return ExampleContextBuilder(
exampleBuilder = ExampleBuilder(
- config = pluginConfig
+ config = pluginConfig.build(PluginConfigData.DEFAULT)
)
).build(routes.toList())
}
@@ -114,12 +116,13 @@ class PathsBuilderTest : StringSpec({
routes: Collection,
schemaContext: SchemaContext,
exampleContext: ExampleContext,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): Paths {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return PathsBuilder(
pathBuilder = PathBuilder(
operationBuilder = OperationBuilder(
- operationTagsBuilder = OperationTagsBuilder(pluginConfig),
+ operationTagsBuilder = OperationTagsBuilder(pluginConfigData),
parameterBuilder = ParameterBuilder(
schemaContext = schemaContext,
exampleContext = exampleContext
@@ -140,9 +143,9 @@ class PathsBuilderTest : StringSpec({
headerBuilder = HeaderBuilder(schemaContext)
)
),
- config = pluginConfig
+ config = pluginConfigData
),
- securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfig),
+ securityRequirementsBuilder = SecurityRequirementsBuilder(pluginConfigData),
)
)
).build(routes)
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/SecuritySchemesBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/SecuritySchemesBuilderTest.kt
index 7e8f8135..96de733c 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/SecuritySchemesBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/SecuritySchemesBuilderTest.kt
@@ -1,11 +1,12 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
-import io.github.smiley4.ktorswaggerui.dsl.AuthKeyLocation
-import io.github.smiley4.ktorswaggerui.dsl.AuthScheme
-import io.github.smiley4.ktorswaggerui.dsl.AuthType
+import io.github.smiley4.ktorswaggerui.data.AuthKeyLocation
+import io.github.smiley4.ktorswaggerui.data.AuthScheme
+import io.github.smiley4.ktorswaggerui.data.AuthType
+import io.github.smiley4.ktorswaggerui.data.SecuritySchemeData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSecurityScheme
-import io.github.smiley4.ktorswaggerui.spec.openapi.OAuthFlowsBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.SecuritySchemesBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.OAuthFlowsBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.SecuritySchemesBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
import io.kotest.matchers.maps.shouldBeEmpty
@@ -191,7 +192,7 @@ class SecuritySchemesBuilderTest : StringSpec({
private fun buildSecuritySchemeObjects(builders: Map Unit>): Map {
return SecuritySchemesBuilder(
oAuthFlowsBuilder = OAuthFlowsBuilder()
- ).build(builders.map { (name, entry) -> OpenApiSecurityScheme(name).apply(entry) })
+ ).build(builders.map { (name, entry) -> OpenApiSecurityScheme(name).apply(entry).build(SecuritySchemeData.DEFAULT) })
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ServersBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ServersBuilderTest.kt
index 0c8c4487..44192f6f 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ServersBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/ServersBuilderTest.kt
@@ -1,7 +1,8 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
+import io.github.smiley4.ktorswaggerui.data.ServerData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiServer
-import io.github.smiley4.ktorswaggerui.spec.openapi.ServerBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.ServerBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.swagger.v3.oas.models.servers.Server
@@ -35,7 +36,7 @@ class ServersBuilderTest : StringSpec({
companion object {
private fun buildServerObject(builder: OpenApiServer.() -> Unit): Server {
- return ServerBuilder().build(OpenApiServer().apply(builder))
+ return ServerBuilder().build(OpenApiServer().apply(builder).build(ServerData.DEFAULT))
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/TagsBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/TagsBuilderTest.kt
index bc2f3356..54123f80 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/TagsBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/openapi/TagsBuilderTest.kt
@@ -1,8 +1,9 @@
package io.github.smiley4.ktorswaggerui.tests.openapi
+import io.github.smiley4.ktorswaggerui.data.TagData
import io.github.smiley4.ktorswaggerui.dsl.OpenApiTag
-import io.github.smiley4.ktorswaggerui.spec.openapi.TagBuilder
-import io.github.smiley4.ktorswaggerui.spec.openapi.TagExternalDocumentationBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.TagBuilder
+import io.github.smiley4.ktorswaggerui.builder.openapi.TagExternalDocumentationBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
@@ -46,7 +47,7 @@ class TagsBuilderTest : StringSpec({
private fun buildTagObject(name: String, builder: OpenApiTag.() -> Unit): Tag {
return TagBuilder(
tagExternalDocumentationBuilder = TagExternalDocumentationBuilder()
- ).build(OpenApiTag(name).apply(builder))
+ ).build(OpenApiTag(name).apply(builder).build(TagData.DEFAULT))
}
}
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/route/RouteDocumentationMergerTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/route/RouteDocumentationMergerTest.kt
index 9a62986c..d4c81249 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/route/RouteDocumentationMergerTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/route/RouteDocumentationMergerTest.kt
@@ -1,7 +1,7 @@
package io.github.smiley4.ktorswaggerui.tests.route
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
-import io.github.smiley4.ktorswaggerui.spec.route.RouteDocumentationMerger
+import io.github.smiley4.ktorswaggerui.builder.route.RouteDocumentationMerger
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
@@ -37,6 +37,7 @@ class RouteDocumentationMergerTest : StringSpec({
"merge complete routes" {
merge(
route {
+ specId = "test-spec-a"
tags = listOf("a1", "a2")
summary = "Summary A"
description = "Description A"
@@ -60,6 +61,7 @@ class RouteDocumentationMergerTest : StringSpec({
}
},
route {
+ specId = "test-spec-b"
tags = listOf("b1", "b2")
summary = "Summary B"
description = "Description B"
@@ -83,6 +85,7 @@ class RouteDocumentationMergerTest : StringSpec({
}
}
).also { route ->
+ route.specId shouldBe "test-spec-a"
route.tags shouldContainExactlyInAnyOrder listOf("a1", "a2", "b1", "b2")
route.summary shouldBe "Summary A"
route.description shouldBe "Description A"
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaBuilderTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaBuilderTest.kt
index 1c1fa311..44ef34d6 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaBuilderTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaBuilderTest.kt
@@ -12,10 +12,10 @@ import com.github.victools.jsonschema.module.swagger2.Swagger2Module
import io.github.smiley4.ktorswaggerui.dsl.Example
import io.github.smiley4.ktorswaggerui.dsl.SchemaEncoder
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaDefinitions
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaTypeAttributeOverride
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaDefinitions
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaTypeAttributeOverride
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.maps.shouldHaveSize
@@ -30,6 +30,35 @@ import kotlin.reflect.jvm.javaType
class SchemaBuilderTest : StringSpec({
+ "victools field names".config(enabled = false) {
+ /**
+ * Test-case for https://github.com/SMILEY4/ktor-swagger-ui/issues/60.
+ * -> victools incorrectly ignores fields with is[A-Z]
+ */
+ createSchemaVictools(false).also { defs ->
+ defs.root.also { schema ->
+ schema.`$ref` shouldBe null
+ schema.type shouldBe "object"
+ schema.properties.keys shouldContainExactly setOf("flag", "getAnotherText", "text", "isSomething", "isSomeText")
+ schema.properties["flag"]!!.also { prop ->
+ prop.type shouldBe "boolean"
+ }
+ schema.properties["isSomething"]!!.also { prop ->
+ prop.type shouldBe "boolean"
+ }
+ schema.properties["text"]!!.also { prop ->
+ prop.type shouldBe "string"
+ }
+ schema.properties["getAnotherText"]!!.also { prop ->
+ prop.type shouldBe "string"
+ }
+ schema.properties["isSomeText"]!!.also { prop ->
+ prop.type shouldBe "string"
+ }
+ }
+ }
+ }
+
"primitive (victools, all definitions)" {
createSchemaVictools(true).also { defs ->
defs.definitions.keys shouldContainExactly setOf("int")
@@ -403,6 +432,14 @@ class SchemaBuilderTest : StringSpec({
)
+ data class WithFieldNames(
+ val flag: Boolean,
+ val isSomething: Boolean,
+ val text: String,
+ val isSomeText: String,
+ val getAnotherText: String
+ )
+
inline fun createSchemaVictools(definitions: Boolean) =
createSchema("\$defs", serializerVictools(definitions))
diff --git a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaContextTest.kt b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaContextTest.kt
index c2012226..f4040d46 100644
--- a/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaContextTest.kt
+++ b/src/test/kotlin/io/github/smiley4/ktorswaggerui/tests/schema/SchemaContextTest.kt
@@ -6,17 +6,18 @@ import com.github.victools.jsonschema.generator.OptionPreset
import com.github.victools.jsonschema.generator.SchemaGenerator
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder
import com.github.victools.jsonschema.generator.SchemaVersion
-import io.github.smiley4.ktorswaggerui.SwaggerUIPluginConfig
+import io.github.smiley4.ktorswaggerui.data.PluginConfigData
+import io.github.smiley4.ktorswaggerui.dsl.PluginConfigDsl
import io.github.smiley4.ktorswaggerui.dsl.OpenApiRoute
-import io.github.smiley4.ktorswaggerui.dsl.array
import io.github.smiley4.ktorswaggerui.dsl.asSchemaType
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
-import io.github.smiley4.ktorswaggerui.dsl.obj
-import io.github.smiley4.ktorswaggerui.spec.route.RouteMeta
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContext
-import io.github.smiley4.ktorswaggerui.spec.schema.SchemaContextBuilder
-import io.github.smiley4.ktorswaggerui.spec.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext
+import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextBuilder
+import io.github.smiley4.ktorswaggerui.builder.schema.TypeOverwrites
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.custom
+import io.github.smiley4.ktorswaggerui.dsl.BodyTypeDescriptor.Companion.multipleOf
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.collections.shouldBeEmpty
import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder
@@ -289,7 +290,7 @@ class SchemaContextTest : StringSpec({
}
"custom schema object" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
openApi("myCustomSchema") {
Schema().also { schema ->
@@ -306,12 +307,12 @@ class SchemaContextTest : StringSpec({
val routes = listOf(
route {
request {
- body(obj("myCustomSchema"))
+ body(custom("myCustomSchema"))
}
}
)
val schemaContext = schemaContext(routes, config)
- schemaContext.getSchema(obj("myCustomSchema")).also { schema ->
+ schemaContext.getSchema("myCustomSchema").also { schema ->
schema.type shouldBe null
schema.`$ref` shouldBe "#/components/schemas/myCustomSchema"
}
@@ -327,7 +328,7 @@ class SchemaContextTest : StringSpec({
}
"custom schema array" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
openApi("myCustomSchema") {
Schema().also { schema ->
@@ -344,19 +345,14 @@ class SchemaContextTest : StringSpec({
val routes = listOf(
route {
request {
- body(array("myCustomSchema"))
+ body(multipleOf(custom("myCustomSchema")))
}
}
)
val schemaContext = schemaContext(routes, config)
- schemaContext.getSchema(array("myCustomSchema")).also { schema ->
- schema.type shouldBe "array"
- schema.`$ref` shouldBe null
- schema.items
- .also { it shouldNotBe null }
- ?.also { items ->
- items.`$ref` shouldBe "#/components/schemas/myCustomSchema"
- }
+ schemaContext.getSchema("myCustomSchema").also { schema ->
+ schema.type shouldBe null
+ schema.`$ref` shouldBe "#/components/schemas/myCustomSchema"
}
schemaContext.getComponentsSection().also { components ->
components.keys shouldContainExactlyInAnyOrder listOf(
@@ -378,7 +374,7 @@ class SchemaContextTest : StringSpec({
.with(Option.ALLOF_CLEANUP_AT_THE_END)
.build()
)
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.encoding {
schemaEncoder { type ->
generator.generateSchema(type.javaType).toString()
@@ -414,7 +410,7 @@ class SchemaContextTest : StringSpec({
}
"don't include unused custom schema" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
includeAll = false
openApi("myCustomSchema") {
@@ -430,14 +426,14 @@ class SchemaContextTest : StringSpec({
}
}
val schemaContext = schemaContext(emptyList(), config)
- schemaContext.getSchemaOrNull(obj("myCustomSchema")) shouldBe null
+ schemaContext.getSchemaOrNull("myCustomSchema") shouldBe null
schemaContext.getComponentsSection().also { components ->
components.keys shouldHaveSize 0
}
}
"include unused custom schema" {
- val config = SwaggerUIPluginConfig().also {
+ val config = PluginConfigDsl().also {
it.customSchemas {
includeAll = true
openApi("myCustomSchema") {
@@ -453,7 +449,7 @@ class SchemaContextTest : StringSpec({
}
}
val schemaContext = schemaContext(emptyList(), config)
- schemaContext.getSchema(obj("myCustomSchema")).also { schema ->
+ schemaContext.getSchema("myCustomSchema").also { schema ->
schema.type shouldBe null
schema.`$ref` shouldBe "#/components/schemas/myCustomSchema"
}
@@ -498,17 +494,18 @@ class SchemaContextTest : StringSpec({
inline fun getType() = getSchemaType()
- private val defaultPluginConfig = SwaggerUIPluginConfig()
+ private val defaultPluginConfig = PluginConfigDsl()
private fun schemaContext(
routes: Collection,
- pluginConfig: SwaggerUIPluginConfig = defaultPluginConfig
+ pluginConfig: PluginConfigDsl = defaultPluginConfig
): SchemaContext {
+ val pluginConfigData = pluginConfig.build(PluginConfigData.DEFAULT)
return SchemaContextBuilder(
- config = pluginConfig,
+ config = pluginConfigData,
schemaBuilder = SchemaBuilder(
- definitionsField = pluginConfig.encodingConfig.schemaDefinitionsField,
- schemaEncoder = pluginConfig.encodingConfig.getSchemaEncoder(),
+ definitionsField = pluginConfigData.encoding.schemaDefsField,
+ schemaEncoder = pluginConfigData.encoding.schemaEncoder,
ObjectMapper(),
TypeOverwrites.get()
)