You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using other web frameworks, I'm used to being able to just return null/nil from handlers in order to say "this handler cannot handle this request", and so the request "falls through" to a later handler. The most common rationale IMO for doing this is to centralize the serving of static assets (and when necessary, 404's) referred to by N different "modules" in monolithic webapps.
Say you have an app with some scopes, corresponding to logically distinct components:
letmain()=
run
@@ router
[ scope "/blog" [] ...
; scope "/feeds" [] ...
; get "/" ...
; get "/**" (Dream.static ~loader:static_loader "")]]
@@fun_r -> Dream.respond ~status:`Not_Found"sorry"
It's not uncommon for pages to refer to static assets within the same prefix, e.g. a blog post at /blog/2021/10/08/foo would typically have any images on that page served from the same directory, so e.g. /blog/2021/10/08/picture.png. However, the static handler in the example above would never see those requests, as they are exclusively handled within the scope provided to the router. Therefore, each scope currently needs its own static asset handler and not-found handler, to accommodate serving those static assets, and issuing 404s as needed for requests within that scope.
(An immediate workaround is to just put all static assets under a dedicated prefix like "/static/**", but (a) that's a silly reason to potentially break extant URLs, and (b) is of little help when integrating content generated by other tools.)
I had expected to find an exception type that Dream.router would catch as a signal to move on to the next handler in the route list…but no such thing exists. My proposal is then that such a thing be added: a custom exception type that any handler can raise to indicate that they can't satisfy the provided request (a "response" distinct from a 404), forcing the router to continue attempting to delegate request handling to the next handler in the chain.
If and until such a thing is available, implementing a somewhat more limited approach is possible using middleware:
exceptionNoResponselethandleNoResponse (failsafe: Dream.handler) (routes: Dream.middleware) =let h = routes failsafe infunrequest ->
try
h request
withNoResponse ->
failsafe request
let static_handler =Dream.static ~loader:static_loader ""letmain()=
run
@@ handleNoResponse static_handler
@@ router
[ scope "/blog" [] ...
; scope "/feeds" [] ...
; get "/" ...
]]
With this arrangement, any handler in the router can raise NoResponse, and the handleNoResponse middleware will ensure that the "failsafe" handler is invoked (which is also used as the last-resort handler for the router). This is slightly less capable than if the router module itself declared and handled such an exception (the handleNoResponse middleware is sort of a top-level catch-all that can't be composed with anything else, in contrast with regular routes and handlers), but gets the job done for my main use case for this pattern.
The text was updated successfully, but these errors were encountered:
e.g. a blog post at /blog/2021/10/08/foo would typically have any images on that page served from the same directory, so e.g. /blog/2021/10/08/picture.png....just put all static assets under a dedicated prefix like "/static/**", but (a) that's a silly reason to potentially break extant URLs
Another option might be to permanent redirect? Eg,
(* Get the rendered post *)letget_blog_postreq= ...
(* Get the rendered post or redirect if request is for a static asset *)letget_blog_resourcereq=let target =Dream.target req inmatchFilename.extension target with|"" -> get_blog_post req
|_ -> Dream.redirect ~status:`Moved_Permanently req ("/static"^ target)
...
Dream.router [
Dream.scope "/blog" [] [
Dream.get "/:year/:month/:day/:resource" get_blog_resource
];
Dream.get "/static/**"@@Dream.static "www/static";
(* Eg /static/blog/2021/10/08/picture.png *)
]
And then update the static URLs in the blog posts at your leisure?
(b) is of little help when integrating content generated by other tools.
Could you give an example of that? I don't immediately get your meaning here.
When using other web frameworks, I'm used to being able to just return null/nil from handlers in order to say "this handler cannot handle this request", and so the request "falls through" to a later handler. The most common rationale IMO for doing this is to centralize the serving of static assets (and when necessary, 404's) referred to by N different "modules" in monolithic webapps.
Say you have an app with some scopes, corresponding to logically distinct components:
It's not uncommon for pages to refer to static assets within the same prefix, e.g. a blog post at
/blog/2021/10/08/foo
would typically have any images on that page served from the same directory, so e.g./blog/2021/10/08/picture.png
. However, the static handler in the example above would never see those requests, as they are exclusively handled within the scope provided to the router. Therefore, each scope currently needs its own static asset handler and not-found handler, to accommodate serving those static assets, and issuing 404s as needed for requests within that scope.(An immediate workaround is to just put all static assets under a dedicated prefix like
"/static/**"
, but (a) that's a silly reason to potentially break extant URLs, and (b) is of little help when integrating content generated by other tools.)I had expected to find an exception type that
Dream.router
would catch as a signal to move on to the next handler in the route list…but no such thing exists. My proposal is then that such a thing be added: a custom exception type that any handler can raise to indicate that they can't satisfy the provided request (a "response" distinct from a 404), forcing the router to continue attempting to delegate request handling to the next handler in the chain.If and until such a thing is available, implementing a somewhat more limited approach is possible using middleware:
With this arrangement, any handler in the router can raise
NoResponse
, and thehandleNoResponse
middleware will ensure that the "failsafe" handler is invoked (which is also used as the last-resort handler for the router). This is slightly less capable than if the router module itself declared and handled such an exception (thehandleNoResponse
middleware is sort of a top-level catch-all that can't be composed with anything else, in contrast with regular routes and handlers), but gets the job done for my main use case for this pattern.The text was updated successfully, but these errors were encountered: