io.javalin.http.HttpResponseExceptionMapper.kt Maven / Gradle / Ivy
The newest version!
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.http
import io.javalin.core.util.Header
import io.javalin.http.util.JsonEscapeUtil
import java.util.*
import java.util.concurrent.CompletionException
object HttpResponseExceptionMapper {
fun canHandle(t: Throwable) = HttpResponseException::class.java.isAssignableFrom(t::class.java) // is HttpResponseException or subclass
fun handle(exception: Exception, ctx: Context) {
val e = unwrap(exception)
if (ctx.header(Header.ACCEPT)?.contains(ContentType.JSON) == true || ctx.res.contentType == ContentType.JSON) {
ctx.status(e.status).result("""{
| "title": "${e.message?.jsonEscape()}",
| "status": ${e.status},
| "type": "${getTypeUrl(e).lowercase(Locale.ROOT)}",
| "details": {${e.details.map { """"${it.key}":"${it.value.jsonEscape()}"""" }.joinToString(",")}}
|}""".trimMargin()
).contentType(ContentType.APPLICATION_JSON)
} else {
val result = if (e.details.isEmpty()) "${e.message}" else """
|${e.message}
|${
e.details.map {
"""
|${it.key}:
|${it.value}
|"""
}.joinToString("")
}""".trimMargin()
ctx.status(e.status).result(result)
}
}
private const val docsUrl = "https://javalin.io/documentation#"
private fun classUrl(e: HttpResponseException) = docsUrl + e.javaClass.simpleName
private fun unwrap(e: Exception) = (if (e is CompletionException) e.cause else e) as HttpResponseException
// this could be removed by introducing a "DefaultResponse", but I would
// rather keep this ugly snippet than introduced another abstraction layer
private fun getTypeUrl(e: HttpResponseException) = when (e) {
is RedirectResponse -> classUrl(e)
is BadRequestResponse -> classUrl(e)
is UnauthorizedResponse -> classUrl(e)
is ForbiddenResponse -> classUrl(e)
is NotFoundResponse -> classUrl(e)
is MethodNotAllowedResponse -> classUrl(e)
is ConflictResponse -> classUrl(e)
is GoneResponse -> classUrl(e)
is InternalServerErrorResponse -> classUrl(e)
is ServiceUnavailableResponse -> classUrl(e)
is BadGatewayResponse -> classUrl(e)
is GatewayTimeoutResponse -> classUrl(e)
else -> docsUrl + "error-responses"
}
private fun String.jsonEscape() = JsonEscapeUtil.escape(this)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy