Error handler based on the request inputs
beajeanm opened this issue · comments
This maybe more a question than a bug/feature request.
The error handler I'm trying to implement has some logic based on the incoming request that generated the error.
If building it from scratch (so implementing Dream.error -> Dream.response option Lwt.t
) then it's all good, I have the (optional) request in error.request
. But I'm missing all the bells an whistle that come with the default error handler. (Smart logging and stack trace in debug mode.)
If I try to go through the template instead (so implementing string option -> response -> response Lwt.t
) I lose access to all the request inputs.
I can see how to workaround the problem for reponse based errors I generated by adding the required data to the reponse locals. But that only cover part of the errors, and it doesn't work for the reponses generated by another middleware (e.g. Dream.not_found
)
Is there something I'm missing?
Is there a way for me to access the logging and backtrace printing without using the error template?
@beajeanm I believe this is the error_handler
https://aantron.github.io/dream/#type-error_handler .
Thank you for your comment, but I know about that type (it's the one I describe in building it from scratch) and I don't see how that documentation address my need: Have the logging and back trace logic without using the template.
@beajeanm If I understood you correctly, you'd like to implement a non-trivial error handler (Dream.error -> Dream.response option Lwt.t
), and you'd like to reuse some of the logic that is found in the default error handler:
dream/src/http/error_handler.ml
Lines 116 to 187 in 52d4da2
To proceed, I suggest writing a similar implementation in your own handler. I see at least two kinds of things that we may need to support you with:
- Some of the logic in the default error handler may be useful as exposed helpers, so you can use it as building blocks in your custom handler.
- Some of the existing helpers currently used by the default error handler might be internal (I didn't look through in detail just now). We may need to expose those helpers, so that your error handler can also call them.
There may be other things to do.
I see that you want
(Smart logging and stack trace in debug mode.)
However, I'm not sure what you mean by smart logging. The default error handler just formats the information in the Dream.error
object in some way, and logs that. Do you want that exposed as a helper, so you can readily do the same logging without the annoyance of writing out and/or maintaining code for it?
The rest of the logic in the default error handler is about the backtrace. It is ultimately just based on Printexc.get_backtrace
, but does a bit of formatting work. Would you like to have a helper that logs the backtrace in exactly the same way as the default error handler?
Could you say exactly which pieces you'd like to reuse?
@aantron I'm exploring using Dream with inertiajs.
I'll spare the details, but for the issue at hands, it boils down to: The handler should either give an HTML response or a JSON response based on a header in the incoming request.
Doing that the error handler by creating one from scratch, means I lose the nice debugging functionalities or I have to re-implement them.
To proceed, I suggest writing a similar implementation in your own handler. I see at least two kinds of things that we may need to support you with:
Some of the logic in the default error handler may be useful as exposed helpers, so you can use it as building blocks in your custom handler.
Some of the existing helpers currently used by the default error handler might be internal (I didn't look through in detail just now). We may need to expose those helpers, so that your error handler can also call them.
I had a look at the default handler code and tried to add it to my own:
- Logging: you are correct, it's simpler that I thought. I can replace the use of
let log = Dream__middleware.Log.sub_log "dream.http"
with the public logging methods and get mostly the same result. - Backtrace: I haven't found a way to make it work without
Dream__pure.Inmost
, if that's not possible, then having something similar todream/src/http/error_handler.ml
Lines 28 to 111 in 52d4da2
Could this be better addressed by passing the request (if available) to the template? Since Dream is in alpha and will remain so for a while, it's not a problem to add an extra argument if that's the best way to solve an issue.
It seems like all the logging will already have been done, and you can generate the correct response based on the request.
If that's on the table, then yes, it would make my error handling implementation trivial 😄
@beajeanm I decided to pass the whole Dream.error
object to the template; see here. The request, if available, is in error.request
. Using the other Dream.error
fields, the template can also access all the information that the surrounding error handler can access.
error.request
is a Dream.request option
. Even though IIRC all error contexts that end up calling the template do have a request, I didn't want to commit to a request always being available when the template is called. There are other error contexts where there is no request available, and in future development, Dream may end up wanting to call the error template in a situation where there is no way to pass it a request object.
Could you take a look? I assume this is enough :)
Yes, that works for me, thanks :)
Ok, it's in master
now :)