diff --git a/javalin-openapi/src/main/java/io/javalin/plugin/openapi/OpenApiPlugin.kt b/javalin-openapi/src/main/java/io/javalin/plugin/openapi/OpenApiPlugin.kt index 7b40e5edd..69f79e0c5 100644 --- a/javalin-openapi/src/main/java/io/javalin/plugin/openapi/OpenApiPlugin.kt +++ b/javalin-openapi/src/main/java/io/javalin/plugin/openapi/OpenApiPlugin.kt @@ -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() + 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() + } } + + } + } } diff --git a/javalin-openapi/src/test/kotlin/io/javalin/examples/HelloWorldMultiSwagger.kt b/javalin-openapi/src/test/kotlin/io/javalin/examples/HelloWorldMultiSwagger.kt new file mode 100644 index 000000000..3faf6bbdf --- /dev/null +++ b/javalin-openapi/src/test/kotlin/io/javalin/examples/HelloWorldMultiSwagger.kt @@ -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() + fun getItems() = items.toList() + fun getItem(id: Int) = items.find { it.id == id } + fun addItem(item: Item) = items.add(item) +} + +val getItemsDocs = document().jsonArray("200") { it.description = "Returns all items" } + +fun getItemsHandler(ctx: Context) { + val users = ItemRepository.getItems() + ctx.json(users) +} + +val getItemDocs = document() + .pathParam("id") + .json("200") { it.description = "Returns item with id" } + .result("404") + +fun getItemHandler(ctx: Context) { + val itemId = ctx.pathParam("id").get() + val item = ItemRepository.getItem(itemId) + if (item == null) { + ctx.status(404) + } else { + ctx.json(item) + } +} + +val addItemDocs = document() + .body() + .result("400") + .result("204") + +fun addItemHandler(ctx: Context) { + val item = ctx.body() + 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("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("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() +}