weavejester / compojure

A concise routing library for Ring/Clojure
Eclipse Public License 1.0
4.08k stars 259 forks source link

access :compojure/route in the response object #191

Closed rutchkiwi closed 4 years ago

rutchkiwi commented 4 years ago

First of all, thanks for this great library!

I would like to access the :compojure/route object in a ring middleware "outside" of defroutes.

This would allow me to automatically log, and get automatically get request timings on a route level.

For example:

(defn request-logging [handler]
  (fn [request]
    (let [
          tic-ns   (. System (nanoTime))
          response (handler request)
          toc-ns   (. System (nanoTime))
          time-ms  (float (/ (- toc-ns tic-ns) 1000000))]
       (jdbc/insert db "logs" {:route (response :compojure/route) :time time-ms}
      response)))

(defroutes app-routes
     (GET "/product/:productid" request
        (format "viewing product %s" (get-in (request [:params :productid]))

(def app 
  (-> app-routes request-logging))

(not actually working code but illustrates my point)

Once I have done that, I'd be able to automatically show the average response times of different routes by some sql like

select route, avg(time) from logs group by route

Note that I want the average time of all product requests, not separate entries for each product.


I believe this could be accomplished by modifying this line: https://github.com/weavejester/compojure/blob/bb2fcc7ffdc910555d24ff64a8e7ffacb2c1c478/src/compojure/core.clj#L137

into something like this:

(let [response (handler (assoc request :compojure/route route-info))]
  (assoc response :compojure/route route-info))

Would you be open to a PR like this? Or is there perhaps already a way to accomplish this withoutout any changes to compojure?

weavejester commented 4 years ago

You can write some middleware that passes :compojure/route to the response map, then use wrap-routes to get it in the right position. So something like:

(defn wrap-response-route-info [handler]
  (fn [request]
    (assoc (handler request) :compojure/route (:compojure/route request))))

(def app
  (wrap-routes handler wrap-response-route-info)
rutchkiwi commented 4 years ago

Ah, how elegant! I see I had not really understood how wrap-routes works.

Thank you so much for the quick reply! :)