ktorio / ktor

Framework for quickly creating connected applications in Kotlin with minimal effort
https://ktor.io
Apache License 2.0
13.09k stars 1.07k forks source link

StatusPage handlers don't have access to the call message being processed #1818

Closed rock3r closed 3 years ago

rock3r commented 4 years ago

Ktor Version and Engine Used (client or server and name) Version 1.3.2, server (Netty) but that's irrelevant

Describe the bug When I register a StatusPage handler, the lambda has this signature:

https://github.com/ktorio/ktor/blob/c453a0e60d9e6ddc84b65c85c95a8347efed9087/ktor-server/ktor-server-core/jvm/src/io/ktor/features/StatusPages.kt#L65

And in turn, when it's later invoked in interceptResponse(), it indeed gets only passed the status code:

https://github.com/ktorio/ktor/blob/c453a0e60d9e6ddc84b65c85c95a8347efed9087/ktor-server/ktor-server-core/jvm/src/io/ktor/features/StatusPages.kt#L73-L90

See at line 86: context.handler(status).

That's fine if you don't need to have any conditional logic in the handler. But there is no way to access the message being intercepted from the handler itself, so if you need to check the contents of the message to decide whether StatusPage should do anything about it or not, you can't.

But there are valid scenarios in which you do want to have conditional logic in the handler; the obvious example is that I may have a 404 Not Found StatusPage set up to provide a custom answer (e.g., a JSON):

install(StatusPages) {
    status(HttpStatusCode.NotFound) { statusCode ->
        val json = generate404ErrorJson(call.request.uri)
        call.respondText(json, ContentType.Application.Json, HttpStatusCode.NotFound)
    }
}

In this case, all works fine until I have to respond with a 404 in some handler. If I have, e.g., a route that contains an ID parameter, that needs to be checked against the DB to know if the resource exists or not. If it doesn't exist, I will want to respond with a 404, but probably I can provide a more helpful error message for that response than the global 404 handler can. But currently that's not possible, since the StatusPage will always end up overwriting whatever content I had already put in my response.

CC @e5l

oleg-larshin commented 4 years ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

e5l commented 3 years ago

Hey @rock3r, Hey, Seb. The subject of PipelineContext is the messages what you're looking for. Could you verify that it works for you?