Feature/swagger UI (#34)
This commit is contained in:
14
.github/workflows/pr_checks.yml
vendored
14
.github/workflows/pr_checks.yml
vendored
@ -5,10 +5,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up JDK 1.14
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 1.14
|
distribution: 'adopt'
|
||||||
|
java-version: '11'
|
||||||
- name: Cache Gradle packages
|
- name: Cache Gradle packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
@ -21,10 +22,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up JDK 1.14
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 1.14
|
distribution: 'adopt'
|
||||||
|
java-version: '11'
|
||||||
- name: Cache Gradle packages
|
- name: Cache Gradle packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
|
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
@ -7,9 +7,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-java@v1
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 1.14
|
distribution: 'adopt'
|
||||||
|
java-version: '11'
|
||||||
- name: Cache Gradle packages
|
- name: Cache Gradle packages
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
with:
|
with:
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -1,5 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.6.1] - April 23rd, 2021
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for Swagger ui
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Set jvm target to 11
|
||||||
|
- Resolved bug for empty params and/or empty response body
|
||||||
|
|
||||||
## [0.6.0] - April 21st, 2021
|
## [0.6.0] - April 21st, 2021
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
20
README.md
20
README.md
@ -144,13 +144,13 @@ At the moment, the basic and jwt authentication is only supported.
|
|||||||
A minimal example would be:
|
A minimal example would be:
|
||||||
```kotlin
|
```kotlin
|
||||||
install(Authentication) {
|
install(Authentication) {
|
||||||
notarizedBasic("basic") {
|
notarizedBasic("basic") {
|
||||||
realm = "Ktor realm 1"
|
realm = "Ktor realm 1"
|
||||||
// ...
|
// configure basic authentication provider..
|
||||||
}
|
}
|
||||||
notarizedJwt("jwt") {
|
notarizedJwt("jwt") {
|
||||||
realm = "Ktor realm 2"
|
realm = "Ktor realm 2"
|
||||||
// ...
|
// configure jwt authentication provider...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
@ -181,7 +181,17 @@ A minimal example would be:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Enabling Swagger ui
|
||||||
|
To enable Swagger UI, `kompendium-swagger-ui` needs to be added.
|
||||||
|
This will also add the [ktor webjars feature](https://ktor.io/docs/webjars.html) to your classpath as it is required for swagger ui.
|
||||||
|
Minimal Example:
|
||||||
|
```kotlin
|
||||||
|
install(Webjars)
|
||||||
|
routing {
|
||||||
|
openApi()
|
||||||
|
swaggerUI()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ allprojects {
|
|||||||
|
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "14"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Kompendium
|
# Kompendium
|
||||||
project.version=0.6.0
|
project.version=0.6.1
|
||||||
# Kotlin
|
# Kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
# Gradle
|
# Gradle
|
||||||
|
@ -3,6 +3,7 @@ kotlin = "1.4.32"
|
|||||||
ktor = "1.5.3"
|
ktor = "1.5.3"
|
||||||
slf4j = "1.7.30"
|
slf4j = "1.7.30"
|
||||||
logback = "1.2.3"
|
logback = "1.2.3"
|
||||||
|
swagger-ui = "3.47.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
# API
|
# API
|
||||||
@ -12,12 +13,16 @@ ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor"
|
|||||||
ktor-html-builder = { group = "io.ktor", name = "ktor-html-builder", version.ref = "ktor" }
|
ktor-html-builder = { group = "io.ktor", name = "ktor-html-builder", version.ref = "ktor" }
|
||||||
ktor-auth-lib = { group = "io.ktor", name = "ktor-auth", version.ref = "ktor" }
|
ktor-auth-lib = { group = "io.ktor", name = "ktor-auth", version.ref = "ktor" }
|
||||||
ktor-auth-jwt = { group = "io.ktor", name = "ktor-auth-jwt", version.ref = "ktor" }
|
ktor-auth-jwt = { group = "io.ktor", name = "ktor-auth-jwt", version.ref = "ktor" }
|
||||||
|
ktor-webjars = { group = "io.ktor", name = "ktor-webjars", version.ref = "ktor" }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
slf4j = { group = "org.slf4j", name = "slf4j-api", version.ref = "slf4j" }
|
||||||
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
|
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
|
||||||
logback-core = { group = "ch.qos.logback", name = "logback-core", version.ref = "logback" }
|
logback-core = { group = "ch.qos.logback", name = "logback-core", version.ref = "logback" }
|
||||||
|
|
||||||
|
# webjars
|
||||||
|
webjars-swagger-ui = { group "org.webjars", name = "swagger-ui", version.ref = "swagger-ui" }
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
ktor = [ "ktor-server-core", "ktor-server-netty", "ktor-jackson", "ktor-html-builder" ]
|
ktor = [ "ktor-server-core", "ktor-server-netty", "ktor-jackson", "ktor-html-builder" ]
|
||||||
ktorAuth = [ "ktor-auth-lib", "ktor-auth-jwt" ]
|
ktorAuth = [ "ktor-auth-lib", "ktor-auth-jwt" ]
|
||||||
|
@ -33,6 +33,7 @@ import org.leafygreens.kompendium.models.oas.OpenApiSpecResponse
|
|||||||
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaRef
|
import org.leafygreens.kompendium.models.oas.OpenApiSpecSchemaRef
|
||||||
import org.leafygreens.kompendium.path.CorePathCalculator
|
import org.leafygreens.kompendium.path.CorePathCalculator
|
||||||
import org.leafygreens.kompendium.path.PathCalculator
|
import org.leafygreens.kompendium.path.PathCalculator
|
||||||
|
import org.leafygreens.kompendium.util.Helpers
|
||||||
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
|
import org.leafygreens.kompendium.util.Helpers.getReferenceSlug
|
||||||
|
|
||||||
object Kompendium {
|
object Kompendium {
|
||||||
@ -123,38 +124,37 @@ object Kompendium {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO These two lookin' real similar 👀 Combine?
|
// TODO These two lookin' real similar 👀 Combine?
|
||||||
private fun KType.toRequestSpec(requestInfo: RequestInfo?): OpenApiSpecRequest? = when (this) {
|
private fun KType.toRequestSpec(requestInfo: RequestInfo?): OpenApiSpecRequest? = when (requestInfo) {
|
||||||
Unit::class -> null
|
null -> null
|
||||||
else -> when (requestInfo) {
|
else -> {
|
||||||
null -> null
|
OpenApiSpecRequest(
|
||||||
else -> OpenApiSpecRequest(
|
|
||||||
description = requestInfo.description,
|
description = requestInfo.description,
|
||||||
content = requestInfo.mediaTypes.associateWith {
|
content = resolveContent(requestInfo.mediaTypes) ?: mapOf()
|
||||||
val ref = getReferenceSlug()
|
|
||||||
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KType.toResponseSpec(responseInfo: ResponseInfo?): Pair<Int, OpenApiSpecResponse>? = when (this) {
|
private fun KType.toResponseSpec(responseInfo: ResponseInfo?): Pair<Int, OpenApiSpecResponse>? = when (responseInfo) {
|
||||||
Unit::class -> null // TODO Maybe not though? could be unit but 200 🤔
|
null -> null // TODO again probably revisit this
|
||||||
else -> when (responseInfo) {
|
else -> {
|
||||||
null -> null // TODO again probably revisit this
|
val specResponse = OpenApiSpecResponse(
|
||||||
else -> {
|
description = responseInfo.description,
|
||||||
val content = responseInfo.mediaTypes.associateWith {
|
content = resolveContent(responseInfo.mediaTypes)
|
||||||
val ref = getReferenceSlug()
|
)
|
||||||
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
|
Pair(responseInfo.status, specResponse)
|
||||||
}
|
|
||||||
val specResponse = OpenApiSpecResponse(
|
|
||||||
description = responseInfo.description,
|
|
||||||
content = content.ifEmpty { null }
|
|
||||||
)
|
|
||||||
Pair(responseInfo.status, specResponse)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun KType.resolveContent(mediaTypes: List<String>): Map<String, OpenApiSpecMediaType>? {
|
||||||
|
return if (this != Helpers.UNIT_TYPE && mediaTypes.isNotEmpty()) {
|
||||||
|
mediaTypes.associateWith {
|
||||||
|
val ref = getReferenceSlug()
|
||||||
|
OpenApiSpecMediaType.Referenced(OpenApiSpecReferenceObject(ref))
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO God these annotations make this hideous... any way to improve?
|
// TODO God these annotations make this hideous... any way to improve?
|
||||||
private fun KType.toParameterSpec(): List<OpenApiSpecParameter> {
|
private fun KType.toParameterSpec(): List<OpenApiSpecParameter> {
|
||||||
val clazz = classifier as KClass<*>
|
val clazz = classifier as KClass<*>
|
||||||
|
@ -11,6 +11,7 @@ import kotlin.reflect.KProperty
|
|||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
import kotlin.reflect.jvm.javaField
|
import kotlin.reflect.jvm.javaField
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
import kotlin.reflect.full.createType
|
||||||
|
|
||||||
object Helpers {
|
object Helpers {
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ object Helpers {
|
|||||||
|
|
||||||
const val COMPONENT_SLUG = "#/components/schemas"
|
const val COMPONENT_SLUG = "#/components/schemas"
|
||||||
|
|
||||||
|
val UNIT_TYPE by lazy { Unit::class.createType() }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple extension function that will take a [Pair] and place it (if absent) into a [MutableMap].
|
* Simple extension function that will take a [Pair] and place it (if absent) into a [MutableMap].
|
||||||
|
@ -324,6 +324,22 @@ internal class KompendiumTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Can notarize route with no request params and no response body`() {
|
||||||
|
withTestApplication({
|
||||||
|
configModule()
|
||||||
|
docs()
|
||||||
|
emptyGet()
|
||||||
|
}) {
|
||||||
|
// do
|
||||||
|
val json = handleRequest(HttpMethod.Get, "/openapi.json").response.content
|
||||||
|
|
||||||
|
// expect
|
||||||
|
val expected = TestData.getFileSnapshot("no_request_params_and_no_response_body.json").trim()
|
||||||
|
assertEquals(expected, json, "The received json spec should match the expected content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Generates the expected redoc`() {
|
fun `Generates the expected redoc`() {
|
||||||
withTestApplication({
|
withTestApplication({
|
||||||
@ -351,6 +367,7 @@ internal class KompendiumTest {
|
|||||||
val testPostInfo = MethodInfo("Test post endpoint", "Post your tests here!", testPostResponse, testRequest)
|
val testPostInfo = MethodInfo("Test post endpoint", "Post your tests here!", testPostResponse, testRequest)
|
||||||
val testPutInfo = MethodInfo("Test put endpoint", "Put your tests here!", testPostResponse, testRequest)
|
val testPutInfo = MethodInfo("Test put endpoint", "Put your tests here!", testPostResponse, testRequest)
|
||||||
val testDeleteInfo = MethodInfo("Test delete endpoint", "testing my deletes", testDeleteResponse)
|
val testDeleteInfo = MethodInfo("Test delete endpoint", "testing my deletes", testDeleteResponse)
|
||||||
|
val emptyTestGetInfo = MethodInfo("No request params and response body", "testing more")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Application.configModule() {
|
private fun Application.configModule() {
|
||||||
@ -486,6 +503,16 @@ internal class KompendiumTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Application.emptyGet() {
|
||||||
|
routing {
|
||||||
|
route("/test/empty") {
|
||||||
|
notarizedGet<Unit, Unit>(emptyTestGetInfo) {
|
||||||
|
call.respond(HttpStatusCode.OK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val oas = Kompendium.openApiSpec.copy(
|
private val oas = Kompendium.openApiSpec.copy(
|
||||||
info = OpenApiSpecInfo(
|
info = OpenApiSpecInfo(
|
||||||
title = "Test API",
|
title = "Test API",
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"openapi" : "3.0.3",
|
||||||
|
"info" : {
|
||||||
|
"title" : "Test API",
|
||||||
|
"version" : "1.33.7",
|
||||||
|
"description" : "An amazing, fully-ish \uD83D\uDE09 generated API spec",
|
||||||
|
"termsOfService" : "https://example.com",
|
||||||
|
"contact" : {
|
||||||
|
"name" : "Homer Simpson",
|
||||||
|
"url" : "https://gph.is/1NPUDiM",
|
||||||
|
"email" : "chunkylover53@aol.com"
|
||||||
|
},
|
||||||
|
"license" : {
|
||||||
|
"name" : "MIT",
|
||||||
|
"url" : "https://github.com/lg-backbone/kompendium/blob/main/LICENSE"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"servers" : [ {
|
||||||
|
"url" : "https://myawesomeapi.com",
|
||||||
|
"description" : "Production instance of my API"
|
||||||
|
}, {
|
||||||
|
"url" : "https://staging.myawesomeapi.com",
|
||||||
|
"description" : "Where the fun stuff happens"
|
||||||
|
} ],
|
||||||
|
"paths" : {
|
||||||
|
"/test/empty" : {
|
||||||
|
"get" : {
|
||||||
|
"tags" : [ ],
|
||||||
|
"summary" : "No request params and response body",
|
||||||
|
"description" : "testing more",
|
||||||
|
"parameters" : [ ],
|
||||||
|
"deprecated" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components" : {
|
||||||
|
"schemas" : { },
|
||||||
|
"securitySchemes" : { }
|
||||||
|
},
|
||||||
|
"security" : [ ],
|
||||||
|
"tags" : [ ]
|
||||||
|
}
|
@ -8,6 +8,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation(projects.kompendiumCore)
|
implementation(projects.kompendiumCore)
|
||||||
implementation(projects.kompendiumAuth)
|
implementation(projects.kompendiumAuth)
|
||||||
|
implementation(projects.kompendiumSwaggerUi)
|
||||||
|
|
||||||
implementation(libs.bundles.ktor)
|
implementation(libs.bundles.ktor)
|
||||||
implementation(libs.bundles.ktorAuth)
|
implementation(libs.bundles.ktorAuth)
|
||||||
|
@ -9,12 +9,15 @@ import io.ktor.auth.Authentication
|
|||||||
import io.ktor.auth.authenticate
|
import io.ktor.auth.authenticate
|
||||||
import io.ktor.auth.UserIdPrincipal
|
import io.ktor.auth.UserIdPrincipal
|
||||||
import io.ktor.features.ContentNegotiation
|
import io.ktor.features.ContentNegotiation
|
||||||
|
import io.ktor.http.HttpStatusCode
|
||||||
import io.ktor.jackson.jackson
|
import io.ktor.jackson.jackson
|
||||||
|
import io.ktor.response.respond
|
||||||
import io.ktor.response.respondText
|
import io.ktor.response.respondText
|
||||||
import io.ktor.routing.route
|
import io.ktor.routing.route
|
||||||
import io.ktor.routing.routing
|
import io.ktor.routing.routing
|
||||||
import io.ktor.server.engine.embeddedServer
|
import io.ktor.server.engine.embeddedServer
|
||||||
import io.ktor.server.netty.Netty
|
import io.ktor.server.netty.Netty
|
||||||
|
import io.ktor.webjars.Webjars
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import org.leafygreens.kompendium.Kompendium
|
import org.leafygreens.kompendium.Kompendium
|
||||||
import org.leafygreens.kompendium.Kompendium.notarizedDelete
|
import org.leafygreens.kompendium.Kompendium.notarizedDelete
|
||||||
@ -40,6 +43,7 @@ import org.leafygreens.kompendium.playground.KompendiumTOC.testSinglePostInfo
|
|||||||
import org.leafygreens.kompendium.playground.KompendiumTOC.testSinglePutInfo
|
import org.leafygreens.kompendium.playground.KompendiumTOC.testSinglePutInfo
|
||||||
import org.leafygreens.kompendium.routes.openApi
|
import org.leafygreens.kompendium.routes.openApi
|
||||||
import org.leafygreens.kompendium.routes.redoc
|
import org.leafygreens.kompendium.routes.redoc
|
||||||
|
import org.leafygreens.kompendium.swagger.swaggerUI
|
||||||
import org.leafygreens.kompendium.util.KompendiumHttpCodes
|
import org.leafygreens.kompendium.util.KompendiumHttpCodes
|
||||||
|
|
||||||
private val oas = Kompendium.openApiSpec.copy(
|
private val oas = Kompendium.openApiSpec.copy(
|
||||||
@ -100,11 +104,13 @@ fun Application.mainModule() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
install(Webjars)
|
||||||
featuresInstalled = true
|
featuresInstalled = true
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
openApi(oas)
|
openApi(oas)
|
||||||
redoc(oas)
|
redoc(oas)
|
||||||
|
swaggerUI()
|
||||||
route("/test") {
|
route("/test") {
|
||||||
route("/{id}") {
|
route("/{id}") {
|
||||||
notarizedGet<ExampleParams, ExampleResponse>(testIdGetInfo) {
|
notarizedGet<ExampleParams, ExampleResponse>(testIdGetInfo) {
|
||||||
@ -128,7 +134,7 @@ fun Application.mainModule() {
|
|||||||
authenticate("basic") {
|
authenticate("basic") {
|
||||||
route("/authenticated/single") {
|
route("/authenticated/single") {
|
||||||
notarizedGet<Unit, Unit>(testAuthenticatedSingleGetInfo) {
|
notarizedGet<Unit, Unit>(testAuthenticatedSingleGetInfo) {
|
||||||
call.respondText("get authentiticated single")
|
call.respond(HttpStatusCode.OK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
kompendium-swagger-ui/build.gradle.kts
Normal file
39
kompendium-swagger-ui/build.gradle.kts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
plugins {
|
||||||
|
`java-library`
|
||||||
|
`maven-publish`
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
implementation(libs.bundles.ktor)
|
||||||
|
api(libs.ktor.webjars)
|
||||||
|
implementation(libs.webjars.swagger.ui)
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
|
||||||
|
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.12.0")
|
||||||
|
testImplementation("io.ktor:ktor-server-test-host:1.5.3")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = "GithubPackages"
|
||||||
|
url = uri("https://maven.pkg.github.com/lg-backbone/kompendium")
|
||||||
|
credentials {
|
||||||
|
username = System.getenv("GITHUB_ACTOR")
|
||||||
|
password = System.getenv("GITHUB_TOKEN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publications {
|
||||||
|
create<MavenPublication>("kompendium") {
|
||||||
|
from(components["kotlin"])
|
||||||
|
artifact(tasks.sourcesJar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package org.leafygreens.kompendium.swagger
|
||||||
|
|
||||||
|
import io.ktor.application.call
|
||||||
|
import io.ktor.response.respondRedirect
|
||||||
|
import io.ktor.routing.Routing
|
||||||
|
import io.ktor.routing.get
|
||||||
|
|
||||||
|
fun Routing.swaggerUI(openApiJsonUrl: String = "/openapi.json") {
|
||||||
|
get("/swagger-ui") {
|
||||||
|
call.respondRedirect("/webjars/swagger-ui/index.html?url=$openApiJsonUrl", true)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
rootProject.name = "kompendium"
|
rootProject.name = "kompendium"
|
||||||
include("kompendium-core")
|
include("kompendium-core")
|
||||||
include("kompendium-auth")
|
include("kompendium-auth")
|
||||||
|
include("kompendium-swagger-ui")
|
||||||
include("kompendium-playground")
|
include("kompendium-playground")
|
||||||
|
|
||||||
// Feature Previews
|
// Feature Previews
|
||||||
|
Reference in New Issue
Block a user