Whenever I hit unknown route in my http4s application it returns 404 error page with Content-Type: text/plain and body:
Not found
How can I force it to always return body as JSON with Content-Type: application/json?
{"message": "Not found"}
I figured out that when I assembly httpApp I can map over it and "adjust" responses:
val httpApp = Router.publicRoutes[F].orNotFound.map(ErrorTranslator.handle)
where ErrorTranslator
just detects responses with status code of client error and Content-Type which is not application/json and then just wraps body into JSON:
object ErrorTranslator {
val ContentType = "Content-Type"
val ApplicationJson = "application/json"
private def translate[F[_]: ConcurrentEffect: Sync](r: Response[F]): Response[F] =
r.headers.get(CaseInsensitiveString(ContentType)).map(_.value) match {
case Some(ApplicationJson) => r
case _ => r.withEntity(r.bodyAsText.map(ErrorView(_))) //wrap reponse body into enity
}
def handle[F[_]: ConcurrentEffect: Sync]: PartialFunction[Response[F], Response[F]] = {
case Status.ClientError(r) => translate(r)
case r => r
}
}
It works, but I wonder if there is maybe some less convoluted solution?
It would be also great if a solution could "translate" other errors, like 400 Bad request into JSON, similarily to presented code.