diff --git a/build.gradle.kts b/build.gradle.kts index 03a22057..76611365 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - kotlin("jvm") version "1.9.25" + kotlin("jvm") version "2.0.21" id("org.jetbrains.dokka") version "1.9.20" apply false id("org.owasp.dependencycheck") version "8.2.1" apply false id("io.gitlab.arturbosch.detekt") version "1.23.0" apply false @@ -8,4 +8,4 @@ plugins { repositories { mavenCentral() -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 52f6185f..759c05c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ kotlin.code.style=official # project id projectGroupId=io.github.smiley4 projectArtifactIdBase=ktor-swagger-ui -projectVersion=3.6.0 +projectVersion=4.0.0 # publishing information projectNameBase=Ktor Swagger UI @@ -16,12 +16,12 @@ projectDeveloperName=smiley4 projectDeveloperUrl=https://github.com/SMILEY4 # dependency versions -versionKtor=2.3.12 +versionKtor=3.0.0 versionSwaggerUI=5.17.11 versionSwaggerParser=2.1.22 versionSchemaKenerator=1.5.0 versionKotlinLogging=7.0.0 versionKotest=5.8.0 -versionKotlinTest=1.9.25 +versionKotlinTest=2.0.21 versionMockk=1.13.12 -versionLogback=1.5.6 \ No newline at end of file +versionLogback=1.5.6 diff --git a/ktor-swagger-ui-examples/build.gradle.kts b/ktor-swagger-ui-examples/build.gradle.kts index 510cfb60..58bec51a 100644 --- a/ktor-swagger-ui-examples/build.gradle.kts +++ b/ktor-swagger-ui-examples/build.gradle.kts @@ -5,7 +5,7 @@ version = projectVersion plugins { kotlin("jvm") - kotlin("plugin.serialization") version "1.9.25" + kotlin("plugin.serialization") version "2.0.21" } repositories { @@ -41,4 +41,4 @@ dependencies { kotlin { jvmToolchain(11) -} \ No newline at end of file +} diff --git a/ktor-swagger-ui/build.gradle.kts b/ktor-swagger-ui/build.gradle.kts index 8a7f9c0f..510c0155 100644 --- a/ktor-swagger-ui/build.gradle.kts +++ b/ktor-swagger-ui/build.gradle.kts @@ -31,7 +31,6 @@ dependencies { val versionMockk: String by project implementation("io.ktor:ktor-server-core-jvm:$versionKtor") - implementation("io.ktor:ktor-server-webjars:$versionKtor") implementation("io.ktor:ktor-server-auth:$versionKtor") implementation("io.ktor:ktor-server-resources:$versionKtor") diff --git a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt index abf08681..20276672 100644 --- a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt +++ b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt @@ -1,5 +1,6 @@ package io.github.smiley4.ktorswaggerui +import io.github.oshai.kotlinlogging.KotlinLogging import io.github.smiley4.ktorswaggerui.builder.example.ExampleContext import io.github.smiley4.ktorswaggerui.builder.example.ExampleContextImpl import io.github.smiley4.ktorswaggerui.builder.openapi.ComponentsBuilder @@ -29,6 +30,7 @@ import io.github.smiley4.ktorswaggerui.builder.route.RouteDocumentationMerger import io.github.smiley4.ktorswaggerui.builder.route.RouteMeta import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContext import io.github.smiley4.ktorswaggerui.builder.schema.SchemaContextImpl +import io.github.smiley4.ktorswaggerui.data.OutputFormat import io.github.smiley4.ktorswaggerui.data.PluginConfigData import io.github.smiley4.ktorswaggerui.dsl.config.PluginConfigDsl import io.github.smiley4.ktorswaggerui.routing.ApiSpec @@ -36,14 +38,9 @@ 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.ktor.server.routing.RoutingRoot import io.swagger.v3.core.util.Json31 -import io.github.oshai.kotlinlogging.KotlinLogging -import io.github.smiley4.ktorswaggerui.data.OutputFormat import io.swagger.v3.core.util.Yaml31 /** @@ -59,10 +56,6 @@ val SwaggerUI = createApplicationPlugin(name = "SwaggerUI", createConfiguration on(MonitoringEvent(ApplicationStarted)) { application -> - if (application.pluginOrNull(Webjars) == null) { - application.install(Webjars) - } - try { val routes = routes(application, config) ApiSpec.setAll(buildOpenApiSpecs(config, routes)) @@ -102,7 +95,7 @@ private fun buildOpenApiSpec(specName: String, pluginConfig: PluginConfigData, r } val openApi = builder(pluginConfig, schemaContext, exampleContext).build(routes) pluginConfig.postBuild?.let { it(openApi, specName) } - when(pluginConfig.outputFormat) { + when (pluginConfig.outputFormat) { OutputFormat.JSON -> Json31.pretty(openApi) to pluginConfig.outputFormat OutputFormat.YAML -> Yaml31.pretty(openApi) to pluginConfig.outputFormat } @@ -114,11 +107,12 @@ private fun buildOpenApiSpec(specName: String, pluginConfig: PluginConfigData, r private fun routes(application: Application, config: PluginConfigData): List { return RouteCollector(RouteDocumentationMerger()) - .collectRoutes({ application.plugin(Routing) }, config) + .collectRoutes({ application.plugin(RoutingRoot) }, config) .map { it.copy(path = "${application.rootPath()}${it.path}") } .toList() } + /** * fix [#97](https://github.com/SMILEY4/ktor-swagger-ui/pull/97) * diff --git a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt index 74831bda..cbc14790 100644 --- a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt +++ b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/builder/route/RouteCollector.kt @@ -10,8 +10,8 @@ import io.ktor.server.routing.HttpMethodRouteSelector import io.ktor.server.routing.OptionalParameterRouteSelector import io.ktor.server.routing.ParameterRouteSelector import io.ktor.server.routing.RootRouteSelector -import io.ktor.server.routing.Route import io.ktor.server.routing.RouteSelector +import io.ktor.server.routing.RoutingNode import io.ktor.server.routing.TrailingSlashRouteSelector import kotlin.reflect.full.isSubclassOf @@ -25,7 +25,7 @@ class RouteCollector( /** * Collect all routes from the given application */ - fun collectRoutes(routeProvider: () -> Route, config: PluginConfigData): Sequence { + fun collectRoutes(routeProvider: () -> RoutingNode, config: PluginConfigData): Sequence { return allRoutes(routeProvider()) .asSequence() .map { route -> @@ -42,7 +42,7 @@ class RouteCollector( } - private fun getDocumentation(route: Route, base: OpenApiRoute): OpenApiRoute { + private fun getDocumentation(route: RoutingNode, base: OpenApiRoute): OpenApiRoute { var documentation = base if (route.selector is DocumentedRouteSelector) { documentation = routeDocumentationMerger.merge(documentation, (route.selector as DocumentedRouteSelector).documentation) @@ -55,13 +55,13 @@ class RouteCollector( } - private fun getMethod(route: Route): HttpMethod { + private fun getMethod(route: RoutingNode): HttpMethod { return (route.selector as HttpMethodRouteSelector).method } @Suppress("CyclomaticComplexMethod") - private fun getPath(route: Route, config: PluginConfigData): String { + private fun getPath(route: RoutingNode, config: PluginConfigData): String { val selector = route.selector return if (isIgnoredSelector(selector, config)) { route.parent?.let { getPath(it, config) } ?: "" @@ -96,7 +96,7 @@ class RouteCollector( } - private fun isProtected(route: Route): Boolean { + private fun isProtected(route: RoutingNode): Boolean { return when (route.selector) { is AuthenticationRouteSelector -> true is TrailingSlashRouteSelector -> false @@ -108,7 +108,7 @@ class RouteCollector( } } - private fun allRoutes(root: Route): List { + private fun allRoutes(root: RoutingNode): List { return (listOf(root) + root.children.flatMap { allRoutes(it) }) .filter { it.selector is HttpMethodRouteSelector } } diff --git a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/DocumentedRouteSelector.kt b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/DocumentedRouteSelector.kt index 9becb49c..93583b5a 100644 --- a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/DocumentedRouteSelector.kt +++ b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/DocumentedRouteSelector.kt @@ -2,7 +2,6 @@ package io.github.smiley4.ktorswaggerui.dsl.routing import io.github.smiley4.ktorswaggerui.dsl.routes.OpenApiRoute import io.ktor.http.HttpMethod -import io.ktor.server.application.ApplicationCall import io.ktor.server.routing.Route import io.ktor.server.routing.RouteSelector import io.ktor.server.routing.RouteSelectorEvaluation @@ -16,9 +15,7 @@ import io.ktor.server.routing.patch import io.ktor.server.routing.post import io.ktor.server.routing.put import io.ktor.server.routing.route -import io.ktor.util.KtorDsl -import io.ktor.util.pipeline.PipelineContext -import io.ktor.util.pipeline.PipelineInterceptor +import io.ktor.utils.io.KtorDsl class DocumentedRouteSelector(val documentation: OpenApiRoute) : RouteSelector() { @@ -29,7 +26,7 @@ class DocumentedRouteSelector(val documentation: OpenApiRoute) : RouteSelector() } } - override fun evaluate(context: RoutingResolveContext, segmentIndex: Int) = RouteSelectorEvaluation.Transparent + override suspend fun evaluate(context: RoutingResolveContext, segmentIndex: Int) = RouteSelectorEvaluation.Transparent override fun toString() = if (includeDocumentedRouteInRouteToString) super.toString() else "" } @@ -94,14 +91,14 @@ fun Route.method( fun Route.get( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { get(path, body) } } fun Route.get( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { get(body) } } @@ -114,7 +111,7 @@ fun Route.get( fun Route.post( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { post(path, body) } } @@ -122,7 +119,7 @@ fun Route.post( @JvmName("postTyped") inline fun Route.post( noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { post(body) } } @@ -131,7 +128,7 @@ inline fun Route.post( inline fun Route.post( path: String, noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { post(path, body) } } @@ -139,7 +136,7 @@ inline fun Route.post( fun Route.post( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { post(body) } } @@ -152,14 +149,14 @@ fun Route.post( fun Route.put( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { put(path, body) } } fun Route.put( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { put(body) } } @@ -167,7 +164,7 @@ fun Route.put( @JvmName("putTyped") inline fun Route.put( noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { put(body) } } @@ -176,7 +173,7 @@ inline fun Route.put( inline fun Route.put( path: String, noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { put(path, body) } } @@ -189,14 +186,14 @@ inline fun Route.put( fun Route.delete( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { delete(path, body) } } fun Route.delete( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { delete(body) } } @@ -210,7 +207,7 @@ fun Route.delete( fun Route.patch( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { patch(path, body) } } @@ -218,7 +215,7 @@ fun Route.patch( @KtorDsl fun Route.patch( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { patch(body) } } @@ -226,7 +223,7 @@ fun Route.patch( @JvmName("patchTyped") inline fun Route.patch( noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { patch(body) } @@ -236,7 +233,7 @@ inline fun Route.patch( inline fun Route.patch( path: String, noinline builder: OpenApiRoute.() -> Unit = { }, - crossinline body: suspend PipelineContext.(R) -> Unit + crossinline body: suspend io.ktor.server.routing.RoutingContext.(R) -> Unit ): Route { return documentation(builder) { patch(path, body) } } @@ -249,14 +246,14 @@ inline fun Route.patch( fun Route.options( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { options(path, body) } } fun Route.options( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { options(body) } } @@ -269,14 +266,14 @@ fun Route.options( fun Route.head( path: String, builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { head(path, body) } } fun Route.head( builder: OpenApiRoute.() -> Unit = { }, - body: PipelineInterceptor + body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { head(body) } } diff --git a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/resources/DocumentedResourceRoutes.kt b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/resources/DocumentedResourceRoutes.kt index fb30d31a..d4d14161 100644 --- a/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/resources/DocumentedResourceRoutes.kt +++ b/ktor-swagger-ui/src/main/kotlin/io/github/smiley4/ktorswaggerui/dsl/routing/resources/DocumentedResourceRoutes.kt @@ -4,11 +4,8 @@ import io.github.smiley4.ktorswaggerui.dsl.routes.OpenApiRoute import io.github.smiley4.ktorswaggerui.dsl.routing.documentation import io.github.smiley4.ktorswaggerui.dsl.routing.method import io.ktor.http.HttpMethod -import io.ktor.server.application.ApplicationCall -import io.ktor.server.resources.handle import io.ktor.server.resources.resource import io.ktor.server.routing.Route -import io.ktor.util.pipeline.PipelineContext //============================// // GET // @@ -16,7 +13,7 @@ import io.ktor.util.pipeline.PipelineContext inline fun Route.get( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -33,7 +30,7 @@ inline fun Route.get( inline fun Route.post( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -50,7 +47,7 @@ inline fun Route.post( inline fun Route.put( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -67,7 +64,7 @@ inline fun Route.put( inline fun Route.delete( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -84,7 +81,7 @@ inline fun Route.delete( inline fun Route.patch( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -101,7 +98,7 @@ inline fun Route.patch( inline fun Route.options( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource { @@ -118,7 +115,7 @@ inline fun Route.options( inline fun Route.head( noinline builder: OpenApiRoute.() -> Unit = { }, - noinline body: suspend PipelineContext.(T) -> Unit + noinline body: suspend io.ktor.server.routing.RoutingContext.() -> Unit ): Route { return documentation(builder) { resource {