Skip to content

Commit

Permalink
[openapi] Extended plugin to support hosting multiple specs (closes #…
Browse files Browse the repository at this point in the history
  • Loading branch information
sauterl committed Nov 18, 2020
1 parent feabaff commit b5cade3
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 17 deletions.
Expand Up @@ -12,39 +12,54 @@ import io.javalin.plugin.openapi.ui.SwaggerRenderer
* Plugin for the the automatic generation of an open api schema.
* The schema can be extracted with [JavalinOpenApi.createSchema].
*/
class OpenApiPlugin(private val options: OpenApiOptions) : Plugin, PluginLifecycleInit {
class OpenApiPlugin(private vararg val options: OpenApiOptions) : Plugin, PluginLifecycleInit {

lateinit var openApiHandler: OpenApiHandler

private val handlerMap = mutableMapOf<String, OpenApiHandler>()

override fun init(app: Javalin) {
openApiHandler = OpenApiHandler(app, options)
if (options.isEmpty()) {
throw IllegalArgumentException("The OpenApiPlugin requires at least one set of Options")
}
openApiHandler = OpenApiHandler(app, options.first())
options.forEach {
it.path?.let { path ->
handlerMap.putIfAbsent(path, OpenApiHandler(app, it))
}
}
}

override fun apply(app: Javalin) {
Util.ensureDependencyPresent(OptionalDependency.SWAGGER_CORE)
if (options.path == null && (options.swagger != null || options.reDoc != null)) {
throw IllegalStateException("""
options.forEach { options ->
if (options.path == null && (options.swagger != null || options.reDoc != null)) {
throw IllegalStateException("""
Swagger or ReDoc is enabled, but there is no endpoint available for the OpenApi schema.
Please use the `path` option of the OpenApiPlugin to set a schema endpoint.
""".trimIndent().replace("\n", " "))
}
}

options.path?.let { path ->
app.get(path, openApiHandler, options.roles)
options.path?.let { path ->
app.get(path, handlerMap[path]!!, options.roles)

options.swagger?.let {
Util.assertWebjarInstalled(OptionalDependency.SWAGGERUI)
app.get(it.path, SwaggerRenderer(options), options.roles)
}
options.swagger?.let {
Util.assertWebjarInstalled(OptionalDependency.SWAGGERUI)
app.get(it.path, SwaggerRenderer(options), options.roles)
}

options.reDoc?.let {
Util.assertWebjarInstalled(OptionalDependency.REDOC)
app.get(it.path, ReDocRenderer(options), options.roles)
}
options.reDoc?.let {
Util.assertWebjarInstalled(OptionalDependency.REDOC)
app.get(it.path, ReDocRenderer(options), options.roles)
}

if (options.swagger != null || options.reDoc != null) {
app.config.enableWebjars()
if (options.swagger != null || options.reDoc != null) {
app.config.enableWebjars()
}
}


}

}
}
@@ -0,0 +1,96 @@
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.examples

import io.javalin.Javalin
import io.javalin.http.Context
import io.javalin.http.InternalServerErrorResponse
import io.javalin.plugin.openapi.OpenApiOptions
import io.javalin.plugin.openapi.OpenApiPlugin
import io.javalin.plugin.openapi.dsl.document
import io.javalin.plugin.openapi.dsl.documented
import io.javalin.plugin.openapi.ui.ReDocOptions
import io.javalin.plugin.openapi.ui.RedocOptionsObject
import io.javalin.plugin.openapi.ui.RedocOptionsTheme
import io.javalin.plugin.openapi.ui.SwaggerOptions
import io.swagger.v3.oas.models.info.Info


data class Item(val id: Int, val name: String, val stock: Int, val price: Double)

object ItemRepository {
private val items = mutableListOf<Item>()
fun getItems() = items.toList()
fun getItem(id: Int) = items.find { it.id == id }
fun addItem(item: Item) = items.add(item)
}

val getItemsDocs = document().jsonArray<User>("200") { it.description = "Returns all items" }

fun getItemsHandler(ctx: Context) {
val users = ItemRepository.getItems()
ctx.json(users)
}

val getItemDocs = document()
.pathParam<Int>("id")
.json<Item>("200") { it.description = "Returns item with id" }
.result<Unit>("404")

fun getItemHandler(ctx: Context) {
val itemId = ctx.pathParam<Int>("id").get()
val item = ItemRepository.getItem(itemId)
if (item == null) {
ctx.status(404)
} else {
ctx.json(item)
}
}

val addItemDocs = document()
.body<Item>()
.result<Unit>("400")
.result<Unit>("204")

fun addItemHandler(ctx: Context) {
val item = ctx.body<Item>()
ItemRepository.addItem(item)
ctx.status(204)
}


fun main() {
val app = Javalin.create {
val fullOpenApiOptions = OpenApiOptions(Info().version("1.0").description("My Application"))
.path("/swagger-docs")
.swagger(SwaggerOptions("/swagger").title("My Swagger Documentation"))
.reDoc(ReDocOptions("/redoc", RedocOptionsObject(
hideDownloadButton = true,
theme = RedocOptionsTheme(
spacingUnit = 10,
isTypographyOptimizeSpeed = true
)
)).title("My ReDoc Documentation"))
.defaultDocumentation { documentation -> documentation.json<InternalServerErrorResponse>("500") }
val itemsOnly = OpenApiOptions(Info().version("1.0").description("My Application"))
.path("/swagger-docs-items")
.swagger(SwaggerOptions("/swagger-items").title("My Swagger Documentation -- ITEMS only"))
.defaultDocumentation { documentation -> documentation.json<InternalServerErrorResponse>("500") }
.ignorePath("/users*")
it.registerPlugin(OpenApiPlugin(fullOpenApiOptions, itemsOnly))
}

with(app) {
get("/users", documented(getUsersDocs, ::getUsersHandler))
get("/users/:id", documented(getUserDocs, ::getUserHandler))
post("/users", documented(addUserDocs, ::addUserHandler))
get("/items", documented(getItemsDocs, ::getItemsHandler))
get("/items/:id", documented(getItemDocs, ::getItemHandler))
post("/items", documented(addItemDocs, ::addItemHandler))
}

app.start()
}

0 comments on commit b5cade3

Please sign in to comment.