Combine handlers
manuel-uberti opened this issue · comments
Hi,
is it possible to combine different handlers (created with make-handler
and each of them wrapped with different middlewares) into one?
I am thinking of something like routes
in Compojure. This is what I have:
(def home-handler
(-> (make-handler routes)
(wrap-defaults
(-> site-defaults
(assoc-in [:security :anti-forgery] false)))
wrap-restful-format
wrap-exceptions
wrap-reload))
(def api-handler
(-> (make-handler routes)
wrap-auth-token
wrap-authentication))
(def admin-handler
(-> (make-handler routes)
wrap-auth-token
wrap-authentication
(wrap-defaults
(-> site-defaults
(assoc-in [:security :anti-forgery] false)))
wrap-restful-format
wrap-exceptions
wrap-reload))
Then, to start up the server:
(defn start-server! []
(reset! server (run-server #'app {:port 8080})))
Where app
should be something like:
(def app
(routes
admin-handler
api-handler
home-handler))
Yes, this is possible, because make-handler
returns a normal Ring-compatible handler.
Hi @malcolmsparks, thanks for the prompt reply.
Problem is: what is routes
supposed to be? I mean, how do I combine the handlers in a single one?
(def app
(routes
admin-handler
api-handler
home-handler))
I see now. Yes, bidi is fully composeable. The bidi equivalent is to combine you route pairs in a vector:
[ ["/a" a] ["/b" b] ["/c" c] ]
That vector can be used in the right-hand-side of parent route pair.
Sorry, I don't understand what you mean.
So it is not a matter of make-handler
? Do I have to work on the routes to get different middleware-wrapped handlers?
To help clarify further, there is a conceptual difference between Compojure and bidi that you should understand. In Compojure it is common to wrap different parts of your URI tree in Ring middleware. For example, you might want to add the wrap-json
middleware to a portion of your routes, and the wrap-cookie
to another portion.
Bidi is a pure router only, and encourages you to give it handlers that are fully pre-wrapped with the Ring middleware you want to use.
I see. So, something like this perhaps?
(defn wrap-handler [handler]
(-> handler
wrap-auth-token
wrap-authentication
(wrap-defaults
(-> site-defaults
(assoc-in [:security :anti-forgery] false)))
wrap-restful-format
wrap-exceptions
wrap-reload))
(def routes
["/admin"
{"" {:get {"" (wrap-handler index-handler)}}
"/login" {:get {"" (wrap-handler unauthorized-handler)}
:post {"" (wrap-handler login-handler)}}
"/logout" (wrap-handler logout-handler)}])
(def admin-handler
(make-handler routes))
Yes - that's right.
One thing is that maps are discouraged because they don't care about ordering - which means that after 7 entries the literal becomes a HashMap (rather than an ArrayMap) and order can change -which is often surprising - use a 'vector of vectors' instead.
Fantastic, thanks again.
Sorry to bring this up again, but the proposed solution doesn't work.
(defn index-handler [request]
(-> (response/ok index-html)
(response/header "content-type" "text/html; charset=utf-8")))
Where response
is [ring.util.http-response :as response]
.
(def routes
["/"
[["" (wrap-handler index-handler)]
;; ...
]])
I am serving an html page, generated server-side with Hiccup, which loads js/main.js
(from resources/public
).
If I start the server with:
(def app
(make-handler routes))
(defn start-server! []
(reset! server (run-server #'app {:port 8080})))
main.js
is not found. However, if I do something like:
(def routes
["/"
[["" index-handler]
;; ...
]])
(def home-handler
(-> (make-handler routes)
(wrap-defaults
(-> site-defaults
(assoc-in [:security :anti-forgery] false)))
wrap-restful-format
wrap-exceptions
wrap-reload))
And pass home-handler
to run-server
, everything works as expected.
If you need more details to understand the problem, please ask.
I'm going to close this one due to the lack of activity.