diff --git a/CHANGELOG.md b/CHANGELOG.md index 623e7d8d6..dbb01ba4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Added +- Support for custom docs path + ### Changed ### Remove diff --git a/core/src/main/kotlin/io/bkbn/kompendium/core/routes/Redoc.kt b/core/src/main/kotlin/io/bkbn/kompendium/core/routes/Redoc.kt index 87790983e..ca6bcd3d5 100644 --- a/core/src/main/kotlin/io/bkbn/kompendium/core/routes/Redoc.kt +++ b/core/src/main/kotlin/io/bkbn/kompendium/core/routes/Redoc.kt @@ -16,12 +16,13 @@ import kotlinx.html.title import kotlinx.html.unsafe /** - * Provides an out-of-the-box route to view docs using ReDoc + * Provides an out-of-the-box route to view docs using ReDoc on the specified [path]. * @param pageTitle Webpage title you wish to be displayed on your docs + * @param route path to docs resource * @param specUrl url to point ReDoc to the OpenAPI json document */ -fun Route.redoc(pageTitle: String = "Docs", specUrl: String = "/openapi.json") { - route("/docs") { +fun Route.redoc(pageTitle: String = "Docs", path: String = "/docs", specUrl: String = "/openapi.json") { + route(path) { get { call.respondHtml(HttpStatusCode.OK) { head { diff --git a/playground/src/main/kotlin/io/bkbn/kompendium/playground/CustomRedocPathPlayground.kt b/playground/src/main/kotlin/io/bkbn/kompendium/playground/CustomRedocPathPlayground.kt new file mode 100644 index 000000000..c4ad7ad02 --- /dev/null +++ b/playground/src/main/kotlin/io/bkbn/kompendium/playground/CustomRedocPathPlayground.kt @@ -0,0 +1,120 @@ +package io.bkbn.kompendium.playground + +import io.bkbn.kompendium.core.metadata.GetInfo +import io.bkbn.kompendium.core.plugin.NotarizedApplication +import io.bkbn.kompendium.core.plugin.NotarizedRoute +import io.bkbn.kompendium.core.routes.redoc +import io.bkbn.kompendium.json.schema.KotlinXSchemaConfigurator +import io.bkbn.kompendium.json.schema.definition.TypeDefinition +import io.bkbn.kompendium.oas.payload.Parameter +import io.bkbn.kompendium.oas.serialization.KompendiumSerializersModule +import io.bkbn.kompendium.playground.util.ExampleResponse +import io.bkbn.kompendium.playground.util.ExceptionResponse +import io.bkbn.kompendium.playground.util.Util.baseSpec +import io.ktor.http.HttpStatusCode +import io.ktor.serialization.kotlinx.json.json +import io.ktor.server.application.Application +import io.ktor.server.application.call +import io.ktor.server.application.install +import io.ktor.server.cio.CIO +import io.ktor.server.engine.embeddedServer +import io.ktor.server.plugins.contentnegotiation.ContentNegotiation +import io.ktor.server.response.respond +import io.ktor.server.routing.Route +import io.ktor.server.routing.get +import io.ktor.server.routing.route +import io.ktor.server.routing.routing +import kotlinx.serialization.json.Json + +fun main() { + embeddedServer( + CIO, + port = 8081, + module = Application::mainModule + ).start(wait = true) +} + +private fun Application.mainModule() { + install(ContentNegotiation) { + json(Json { + serializersModule = KompendiumSerializersModule.module + encodeDefaults = true + explicitNulls = false + }) + } + install(NotarizedApplication()) { + spec = baseSpec + // Adds support for @Transient and @SerialName + // If you are not using them this is not required. + schemaConfigurator = KotlinXSchemaConfigurator() + } + routing { + redoc(pageTitle = "Simple API Docs", path = "/api-docs") + + route("/{id}") { + idDocumentation() + get { + call.respond(HttpStatusCode.OK, ExampleResponse(true)) + } + route("/profile") { + profileDocumentation() + get { + call.respond(HttpStatusCode.OK, ExampleResponse(true)) + } + } + } + } +} + +private fun Route.idDocumentation() { + install(NotarizedRoute()) { + parameters = listOf( + Parameter( + name = "id", + `in` = Parameter.Location.path, + schema = TypeDefinition.STRING + ) + ) + get = GetInfo.builder { + summary("Get user by id") + description("A very neat endpoint!") + response { + responseCode(HttpStatusCode.OK) + responseType() + description("Will return whether or not the user is real 😱") + } + + canRespond { + responseType() + responseCode(HttpStatusCode.NotFound) + description("Indicates that a user with this id does not exist") + } + } + } +} + +private fun Route.profileDocumentation() { + install(NotarizedRoute()) { + parameters = listOf( + Parameter( + name = "id", + `in` = Parameter.Location.path, + schema = TypeDefinition.STRING + ) + ) + get = GetInfo.builder { + summary("Get a users profile") + description("A cool endpoint!") + response { + responseCode(HttpStatusCode.OK) + responseType() + description("Returns user profile information") + } + canRespond { + responseType() + responseCode(HttpStatusCode.NotFound) + description("Indicates that a user with this id does not exist") + } + } + } +}