diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt index 89ed2017..7ff6aa48 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt @@ -1,5 +1,7 @@ package io.github.smiley4.ktorswaggerui +import io.github.smiley4.ktorswaggerui.dsl.SwaggerUI +import io.github.smiley4.ktorswaggerui.dsl.SwaggerUiSort import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode import io.ktor.http.content.OutgoingContent @@ -12,7 +14,8 @@ import java.net.URL class SwaggerController( private val swaggerWebjarVersion: String, private val apiSpecUrl: String, - private val jsonSpecProvider: () -> String + private val jsonSpecProvider: () -> String, + private val swaggerUiConfig: SwaggerUI ) { suspend fun serveOpenApiSpec(call: ApplicationCall) { @@ -27,6 +30,12 @@ class SwaggerController( } 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() { // @@ -41,7 +50,12 @@ class SwaggerController( plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], - layout: "StandaloneLayout" + layout: "StandaloneLayout", + $propValidatorUrl, + $propDisplayOperationId, + $propFilter, + $propSort, + $propSyntaxHighlight }); // }; diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt index 0ea348d5..7054cbda 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt @@ -25,9 +25,7 @@ val SwaggerUI = createApplicationPlugin(name = "SwaggerUI", createConfiguration } SwaggerRouting( - pluginConfig.getSwaggerUI().swaggerUrl, - pluginConfig.getSwaggerUI().forwardRoot, - pluginConfig.getSwaggerUI().authentication, + pluginConfig.getSwaggerUI() , application.environment.config, SWAGGER_UI_WEBJARS_VERSION, ) { apiSpecJson }.setup(application) diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt index c21d6af3..0172ca6f 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerRouting.kt @@ -1,5 +1,6 @@ package io.github.smiley4.ktorswaggerui +import io.github.smiley4.ktorswaggerui.dsl.SwaggerUI import io.ktor.server.application.Application import io.ktor.server.application.call import io.ktor.server.auth.authenticate @@ -15,9 +16,7 @@ import mu.KotlinLogging * Registers and handles routes required for the swagger-ui */ class SwaggerRouting( - private val swaggerUrl: String, - private val forwardRoot: Boolean, - private val authentication: String?, + private val swaggerUiConfig: SwaggerUI, appConfig: ApplicationConfig, swaggerWebjarVersion: String, jsonSpecProvider: () -> String @@ -28,12 +27,13 @@ class SwaggerRouting( private val controller = SwaggerController( swaggerWebjarVersion = swaggerWebjarVersion, apiSpecUrl = getApiSpecUrl(appConfig), - jsonSpecProvider = jsonSpecProvider + jsonSpecProvider = jsonSpecProvider, + swaggerUiConfig = swaggerUiConfig ) private fun getApiSpecUrl(appConfig: ApplicationConfig): String { val rootPath = appConfig.propertyOrNull("ktor.deployment.rootPath")?.getString()?.let { "/${dropSlashes(it)}" } ?: "" - return "$rootPath/${dropSlashes(swaggerUrl)}/api.json" + return "$rootPath/${dropSlashes(swaggerUiConfig.swaggerUrl)}/api.json" } private fun dropSlashes(str: String): String { @@ -43,11 +43,13 @@ class SwaggerRouting( 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) { @@ -66,6 +68,7 @@ class SwaggerRouting( } private fun Route.setupSwaggerRoutes() { + val swaggerUrl = swaggerUiConfig.swaggerUrl route(swaggerUrl) { get { call.respondRedirect("$swaggerUrl/index.html") diff --git a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUI.kt b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUI.kt index 7437568d..1641af41 100644 --- a/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUI.kt +++ b/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/SwaggerUI.kt @@ -8,16 +8,83 @@ class SwaggerUI { */ var forwardRoot: Boolean = false - /** * the url to the swagger-ui */ var swaggerUrl: String = "swagger-ui" - /** * The name of the authentication to use for the swagger routes. Null to not protect the swagger-ui. */ var authentication: String? = null + /** + * Swagger UI can attempt to validate specs against swagger.io's online validator. + * You can use this parameter to set a different validator URL, for example for locally deployed validators. + * Set to "null" to disable validation. + * 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 + + fun disableSpecValidator() { + validatorUrl = null + } + + fun specValidator(url: String) { + validatorUrl = url + } + + fun onlineSpecValidator() { + specValidator("https://validator.swagger.io/validator") + } + + fun getSpecValidatorUrl() = validatorUrl + + /** + * Whether to show the operation-id of endpoints in the list + */ + var displayOperationId = false + + /** + * Whether the top bar will show an edit box that you can use to filter the tagged operations. + */ + var showTagFilterInput = false + + /** + * Apply a sort to the operation list of each API + */ + var sort = SwaggerUiSort.NONE + + /** + * Syntax coloring theme to use + */ + var syntaxHighlight = SwaggerUiSyntaxHighlight.AGATE + +} + +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") +} + +enum class SwaggerUiSyntaxHighlight(val value: String) { + AGATE("agate"), + ARTA("arta"), + MONOKAI("monokai"), + NORD("nord"), + OBSIDIAN("obsidian"), + TOMORROW_NIGHT("tomorrow-night") } \ No newline at end of file