ServerResponse
has a method writeTo
which can be used to write your body to ServerExchange
(Spring framework does it this way). Only problem is that you have to provide Context
as a second parameter, so I have just copied HandlerStrategiesResponseContext
from framework implementation.
Make sure that you are using at least Spring Boot 2.0.0 M2, before this version WebExceptionHandler
was not registered while using RouterFunctions
.
import org.springframework.http.HttpStatus
import org.springframework.http.HttpStatus.*
import org.springframework.http.codec.HttpMessageWriter
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.HandlerStrategies
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.result.view.ViewResolver
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebExceptionHandler
@Component
class GlobalErrorHandler() : WebExceptionHandler {
override fun handle(exchange: ServerWebExchange, ex: Throwable): Mono<Void> =
handle(ex)
.flatMap {
it.writeTo(exchange, HandlerStrategiesResponseContext(HandlerStrategies.withDefaults()))
}
.flatMap {
Mono.empty<Void>()
}
fun handle(throwable: Throwable): Mono<ServerResponse> {
return when (throwable) {
is EntityNotFoundException -> {
createResponse(NOT_FOUND, "NOT_FOUND", "Entity not found, details: ${throwable.message}")
}
else -> {
createResponse(INTERNAL_SERVER_ERROR, "GENERIC_ERROR", "Unhandled exception")
}
}
}
fun createResponse(httpStatus: HttpStatus, code: String, message: String): Mono<ServerResponse> =
ServerResponse.status(httpStatus).syncBody(ApiError(code, message))
}
private class HandlerStrategiesResponseContext(val strategies: HandlerStrategies) : ServerResponse.Context {
override fun messageWriters(): List<HttpMessageWriter<*>> {
return this.strategies.messageWriters()
}
override fun viewResolvers(): List<ViewResolver> {
return this.strategies.viewResolvers()
}
}