com.papsign.ktor.openapigen.interop.StatusPages.kt Maven / Gradle / Ivy
package com.papsign.ktor.openapigen.interop
import com.papsign.ktor.openapigen.APIException.Companion.apiException
import com.papsign.ktor.openapigen.OpenAPIGen
import com.papsign.ktor.openapigen.modules.registerModule
import com.papsign.ktor.openapigen.route.ThrowsInfo
import io.ktor.http.HttpStatusCode
import io.ktor.server.plugins.statuspages.StatusPagesConfig
import io.ktor.server.response.respond
/**
* Wraps [StatusPages.Configuration] to enable OpenAPI configuration for exception handling.
* ```
* val api = install(OpenAPIGen) { ... }
* ...
* // StatusPage interop, can also define exceptions per-route
* install(StatusPages) {
* withAPI(api) {
* exception(HttpStatusCode.BadRequest) {
* it.printStackTrace()
* Error("mapping.json", it.localizedMessage)
* }
* exception(HttpStatusCode.BadRequest) {
* it.printStackTrace()
* Error(it.id, it.localizedMessage)
* }
* }
* }
* ```
*
* @param api the installed instance of [OpenAPIGen] in the [io.ktor.application.Application]
* @param cfg the block that loads the configuration, see [OpenAPIGenStatusPagesInterop]
*/
inline fun StatusPagesConfig.withAPI(api: OpenAPIGen, crossinline cfg: OpenAPIGenStatusPagesInterop.() -> Unit = {}) {
OpenAPIGenStatusPagesInterop(api, this).cfg()
}
/**
* Wrapper for Status pages that handles exceptions and generates documentation in OpenAPI.
* This is useful for default error pages.
*/
class OpenAPIGenStatusPagesInterop(val api: OpenAPIGen, val statusCfg: StatusPagesConfig) {
/**
* Registers a handler for exception type [TThrowable] and returns a [status] page
*/
inline fun exception(status: HttpStatusCode) {
val ex = apiException(status)
api.globalModuleProvider.registerModule(ThrowsInfo(listOf(ex)))
statusCfg.exception { call, _ ->
call.respond(status)
}
}
/**
* Registers a handler for exception type [TThrowable] and returns a [status] page that includes a response body
* of type [TResponse].
*
* @param example An example of the response body
* @param gen handler for [TThrowable] that should return an instance of [TResponse]
*/
inline fun exception(
status: HttpStatusCode,
example: TResponse? = null,
noinline gen: (TThrowable) -> TResponse
) {
val ex = apiException(status, example, gen)
api.globalModuleProvider.registerModule(ThrowsInfo(listOf(ex)))
statusCfg.exception { call, cause ->
val ret = gen(cause)
if (ret != null) {
call.respond(status, ret)
} else {
call.respond(status)
}
}
}
}