metosin / reitit

A fast data-driven routing library for Clojure/Script

Home Page:https://cljdoc.org/d/metosin/reitit/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add middleware to support both sync and async handler functions in same route tree

Deraen opened this issue · comments

Usually, the Ring adapter can't choose automatically if the handler function is async (three arguments arity) or synchronous (one argument). When using the async option, the adapter calls the handler function with three arguments, and all middleware and eventually the route handler functions are also called with three arguments. It is still possible to call a synchronous handler function from an async handler function, but it is impossible to reliably inspect if the Clojure function has 1 or 3 argument arity.

With Reitit, we can use route data to mark routes with async handler functions and call sync handler from the async function for the marked routes:

(def async-support
  {:compile (fn async-support-compile [route-data _]
              (if (:async route-data)
                (fn [handler] handler)
                (fn async-support-sync-wrap [handler]
                  (fn async-support-sync-handler [req respond raise]
                    (try
                      (respond (handler req))
                      (catch Exception e
                        (raise e)))))))
   ;; todo: spec
  })

; example

(ring/router
  [""
   ["/sync" {:get {:handler (fn [req] (resp/ok))}}]
   ["/async" {:get {:async true
                    :handler (fn [req respond raise] (do-something respond))}}]]
  {:data {:async false
          :middleware [async-support]]}})