juxt / bidi

Bidirectional URI routing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.