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 Aug 29, 2023
2 parents eed9643 + e7c937a commit cdff00e
Show file tree
Hide file tree
Showing 15 changed files with 115 additions and 81 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Ktor Swagger-UI

[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.smiley4/ktor-swagger-ui/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.smiley4/ktor-swagger-ui)
[![Checks Passing](https://github.com/SMILEY4/ktor-swagger-ui/actions/workflows/buildTestVerify.yml/badge.svg?branch=develop)](https://github.com/SMILEY4/ktor-swagger-ui/actions/workflows/buildTestVerify.yml)
[![Checks Passing](https://github.com/SMILEY4/ktor-swagger-ui/actions/workflows/checks.yml/badge.svg?branch=develop)](https://github.com/SMILEY4/ktor-swagger-ui/actions/workflows/checks.yml)


This library provides a Ktor plugin to document routes, generate an OpenApi Specification and serve a Swagger UI. It is meant to be minimally invasive, meaning it can be plugged into existing application without requiring immediate changes to the code. Routes can then be gradually enhanced with documentation.
Expand Down
2 changes: 1 addition & 1 deletion 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.3.1"
const val version = "2.4.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
2 changes: 1 addition & 1 deletion config/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,6 @@ style:
active: true
ignoreLateinitVar: false
WildcardImport:
active: true
active: false
excludeImports:
- 'java.util.*'
42 changes: 7 additions & 35 deletions src/main/kotlin/io/github/smiley4/ktorswaggerui/SwaggerPlugin.kt
Original file line number Diff line number Diff line change
@@ -1,51 +1,22 @@
package io.github.smiley4.ktorswaggerui

import com.fasterxml.jackson.databind.ObjectMapper
import io.github.smiley4.ktorswaggerui.dsl.SchemaType
import io.github.smiley4.ktorswaggerui.dsl.getSchemaType
import io.github.smiley4.ktorswaggerui.spec.example.ExampleContext
import io.github.smiley4.ktorswaggerui.spec.example.ExampleContextBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ComponentsBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ContactBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ContentBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ExternalDocumentationBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.HeaderBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.InfoBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.LicenseBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.OAuthFlowsBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.OpenApiBuilder
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.openapi.SecuritySchemesBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ServerBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.TagBuilder
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.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.application.*
import io.ktor.server.application.hooks.*
import io.ktor.server.routing.*
import io.ktor.server.webjars.*
import io.swagger.v3.core.util.Json
import mu.KotlinLogging
import java.io.File

/**
* This version must match the version of the gradle dependency
Expand Down Expand Up @@ -112,9 +83,10 @@ private fun builder(config: SwaggerUIPluginConfig, schemaContext: SchemaContext,
contactBuilder = ContactBuilder(),
licenseBuilder = LicenseBuilder()
),
externalDocumentationBuilder = ExternalDocumentationBuilder(),
serverBuilder = ServerBuilder(),
tagBuilder = TagBuilder(
externalDocumentationBuilder = ExternalDocumentationBuilder()
tagExternalDocumentationBuilder = TagExternalDocumentationBuilder()
),
pathsBuilder = PathsBuilder(
pathBuilder = PathBuilder(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
package io.github.smiley4.ktorswaggerui

import io.github.smiley4.ktorswaggerui.dsl.CustomSchemas
import io.github.smiley4.ktorswaggerui.dsl.EncodingConfig
import io.github.smiley4.ktorswaggerui.dsl.OpenApiDslMarker
import io.github.smiley4.ktorswaggerui.dsl.OpenApiInfo
import io.github.smiley4.ktorswaggerui.dsl.OpenApiResponse
import io.github.smiley4.ktorswaggerui.dsl.OpenApiSecurityScheme
import io.github.smiley4.ktorswaggerui.dsl.OpenApiServer
import io.github.smiley4.ktorswaggerui.dsl.OpenApiTag
import io.github.smiley4.ktorswaggerui.dsl.SwaggerUIDsl
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.server.routing.RouteSelector
import io.github.smiley4.ktorswaggerui.dsl.*
import io.ktor.http.*
import io.ktor.server.routing.*
import kotlin.reflect.KClass

/**
Expand Down Expand Up @@ -101,6 +92,18 @@ class SwaggerUIPluginConfig {
fun getServers(): List<OpenApiServer> = 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
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.github.smiley4.ktorswaggerui.dsl

/**
* An object representing external documentation.
*/
@OpenApiDslMarker
class OpenApiExternalDocs {
/**
* A short description of the external documentation
*/
var description: String? = null

/**
* A URL to the external documentation
*/
var url: String = "/"
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.github.smiley4.ktorswaggerui.spec.openapi

import io.github.smiley4.ktorswaggerui.dsl.OpenApiExternalDocs
import io.swagger.v3.oas.models.ExternalDocumentation


class ExternalDocumentationBuilder {

fun build(url: String, description: String): ExternalDocumentation =
fun build(externalDocs: OpenApiExternalDocs): ExternalDocumentation =
ExternalDocumentation().also {
it.url = url
it.description = description
it.url = externalDocs.url
it.description = externalDocs.description
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class OpenApiBuilder(
private val schemaContext: SchemaContext,
private val exampleContext: ExampleContext,
private val infoBuilder: InfoBuilder,
private val externalDocumentationBuilder: ExternalDocumentationBuilder,
private val serverBuilder: ServerBuilder,
private val tagBuilder: TagBuilder,
private val pathsBuilder: PathsBuilder,
Expand All @@ -20,6 +21,7 @@ class OpenApiBuilder(
fun build(routes: Collection<RouteMeta>): 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.paths = pathsBuilder.build(routes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import io.github.smiley4.ktorswaggerui.dsl.OpenApiTag
import io.swagger.v3.oas.models.tags.Tag

class TagBuilder(
private val externalDocumentationBuilder: ExternalDocumentationBuilder
private val tagExternalDocumentationBuilder: TagExternalDocumentationBuilder
) {

fun build(tag: OpenApiTag): Tag =
Tag().also {
it.name = tag.name
it.description = tag.description
if(tag.externalDocUrl != null && tag.externalDocDescription != null) {
it.externalDocs = externalDocumentationBuilder.build(tag.externalDocUrl!!, tag.externalDocDescription!!)
it.externalDocs = tagExternalDocumentationBuilder.build(tag.externalDocUrl!!, tag.externalDocDescription!!)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.smiley4.ktorswaggerui.spec.openapi

import io.swagger.v3.oas.models.ExternalDocumentation

class TagExternalDocumentationBuilder {

fun build(url: String, description: String): ExternalDocumentation =
ExternalDocumentation().also {
it.url = url
it.description = description
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ private fun Application.myModule() {
version = "latest"
description = "Example API for testing and demonstration purposes."
}
externalDocs {
url = "https://github.com/SMILEY4/ktor-swagger-ui/wiki"
description = "Sample external documentation object"
}
server {
url = "http://localhost:8080"
description = "Development Server"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ private fun Application.myModule() {
url = "example.com/license"
}
}
externalDocs {
url = "https://docs.example.com"
description = "Example external documentation description"
}
server {
url = "localhost:8080"
description = "develop server"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.github.smiley4.ktorswaggerui.tests.openapi

import io.github.smiley4.ktorswaggerui.dsl.OpenApiExternalDocs
import io.github.smiley4.ktorswaggerui.spec.openapi.ExternalDocumentationBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe
import io.swagger.v3.oas.models.ExternalDocumentation

class ExternalDocsBuilderTest : StringSpec({

"default external docs object" {
buildExternalDocsObject {}.also { docs ->
docs.url shouldBe "/"
docs.description shouldBe null
}
}

"complete server object" {
buildExternalDocsObject {
url = "Test URL"
description = "Test Description"
}.also { docs ->
docs.url shouldBe "Test URL"
docs.description shouldBe "Test Description"
}
}

}) {

companion object {

private fun buildExternalDocsObject(builder: OpenApiExternalDocs.() -> Unit): ExternalDocumentation {
return ExternalDocumentationBuilder().build(OpenApiExternalDocs().apply(builder))
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,7 @@ 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.ComponentsBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ContactBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ContentBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ExampleBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ExternalDocumentationBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.HeaderBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.InfoBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.LicenseBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.OAuthFlowsBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.OpenApiBuilder
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.openapi.SecuritySchemesBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.ServerBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.TagBuilder
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
Expand All @@ -47,6 +26,7 @@ class OpenApiBuilderTest : StringSpec({
openapi.info shouldNotBe null
openapi.extensions shouldBe null
openapi.servers shouldHaveSize 0
openapi.externalDocs shouldNotBe null
openapi.security shouldBe null
openapi.tags shouldHaveSize 0
openapi.paths shouldHaveSize 0
Expand Down Expand Up @@ -130,9 +110,10 @@ class OpenApiBuilderTest : StringSpec({
contactBuilder = ContactBuilder(),
licenseBuilder = LicenseBuilder()
),
externalDocumentationBuilder = ExternalDocumentationBuilder(),
serverBuilder = ServerBuilder(),
tagBuilder = TagBuilder(
externalDocumentationBuilder = ExternalDocumentationBuilder()
tagExternalDocumentationBuilder = TagExternalDocumentationBuilder()
),
pathsBuilder = PathsBuilder(
pathBuilder = PathBuilder(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.github.smiley4.ktorswaggerui.tests.openapi

import io.github.smiley4.ktorswaggerui.dsl.OpenApiTag
import io.github.smiley4.ktorswaggerui.spec.openapi.ExternalDocumentationBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.TagBuilder
import io.github.smiley4.ktorswaggerui.spec.openapi.TagExternalDocumentationBuilder
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
Expand Down Expand Up @@ -45,7 +45,7 @@ class TagsBuilderTest : StringSpec({

private fun buildTagObject(name: String, builder: OpenApiTag.() -> Unit): Tag {
return TagBuilder(
externalDocumentationBuilder = ExternalDocumentationBuilder()
tagExternalDocumentationBuilder = TagExternalDocumentationBuilder()
).build(OpenApiTag(name).apply(builder))
}

Expand Down

0 comments on commit cdff00e

Please sign in to comment.