Skip to content

Commit

Permalink
Merge branch 'develop' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
SMILEY4 committed Oct 20, 2023
2 parents 195eafa + 92e8b8f commit 6ac0055
Show file tree
Hide file tree
Showing 105 changed files with 2,325 additions and 1,135 deletions.
9 changes: 9 additions & 0 deletions HowToRelease.md
Original file line number Diff line number Diff line change
@@ -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`
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")

Expand Down
104 changes: 0 additions & 104 deletions src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerController.kt

This file was deleted.

143 changes: 107 additions & 36 deletions src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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<String, String>()
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<RouteMeta> {
private fun buildOpenApiSpecs(config: PluginConfigData, routes: List<RouteMeta>): Map<String, String> {
val routesBySpec = buildMap<String, MutableList<RouteMeta>> {
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<RouteMeta>): 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<RouteMeta> {
return RouteCollector(RouteDocumentationMerger())
.collectRoutes({ application.plugin(Routing) }, pluginConfig)
.collectRoutes({ application.plugin(Routing) }, config)
.toList()
}

private fun schemaContext(pluginConfig: SwaggerUIPluginConfig, routes: List<RouteMeta>): SchemaContext {
private fun schemaContext(config: PluginConfigData, routes: List<RouteMeta>): 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<RouteMeta>): ExampleContext {
private fun exampleContext(config: PluginConfigData, routes: List<RouteMeta>): 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,
Expand Down
Loading

0 comments on commit 6ac0055

Please sign in to comment.