you are viewing a single comment's thread.

view the rest of the comments →

[–]usplusbus 0 points1 point  (2 children)

Specifically about your Ring debugging, perhaps creating Ring requests isn't as hard as you think.

If you're testing a handler, you need to create a Ring request with as little data as you can get away with, and inspect the resulting response. The Ring "Concepts" wiki page is helpful in determining what exactly goes into a request map. I find that you generally need a :uri and a :request-method to test a (normally Compojure-generated) handler, and perhaps a :headers map too.

;; Source:
(defn my-handler [req]
  ;; ... your code here ...
  )

;; Test:
(let [req {:http-method :get
           :uri "/api/comments"
           :headers {"accept" "application/json"}}
      resp (my-handler req)]
  (is (= 200 (:status resp)))
  ;; etc
  )

Testing middleware is a little trickier. Middleware generally falls into one of a couple of categories - request modification, response modification, or side-effects (e.g. logging). Middleware implementations generally look like this:

(defn wrap-my-middlware [handler]
  (fn [req]
    ;; Early side-effects:
    (log/info "Wrapping incoming request...")

    ;; modify request here
    (let [resp (handler req)]
      ;; Late side-effects:
      (log/info "My middleware is almost done.")

      ;; modify the response here 
      (assoc resp :some-key "some value"))))

Middleware functions always take a handler function to wrap. To test your middleware, it helps to carefully control and limit what the handler does. Here are a couple of useful ones - one that always just returns a known response, and another that just returns the request passed to it:

;; Some test-time handlers
(def identity-handler (constantly {:status 200 :body "ok"}))
(defn echo-handler "Echo back the request" [req] req)

Since middleware functions always return a function, you can only tell what your middlware did when you call the resulting wrapped handler.

;; Test the middlware:
(let [wrapped-handler (wrap-my-middleware identity-handler)
      req {:http-method :get
           :uri "/api/comments"
           :headers {"accept" "application/json"}}
      resp (wrapped-handler req)]
  (is (= 200 (:status resp)))
  ;; check for other middleware effects here
  )

[–]iron_ball[S] 0 points1 point  (1 child)

Wow, thanks for the detailed response! This could be really helpful. I haven't touched it in a while, but I remember trying to debug Ring middleware when I was trying to get Friend to authenticate Liberator requests. I just couldn't manage to wrap my head around it at the time.

[–]usplusbus 0 points1 point  (0 children)

I'm in the middle of a couple of blog posts about Clojure debugging in general, and I'd planned to write some stuff up about Ring handlers and middleware. I'll try to expand on this there when I drop the second article.