Help understanding Compojure routes and Ring handlers

316 views
Skip to first unread message

Tim McIver

unread,
Jan 2, 2011, 12:48:26 PM1/2/11
to Compojure
I'm new to Clojure, Ring, Compojure, etc. I'm having some trouble
understanding both Compojure routes and Ring handlers, which I've come
to learn are essentially the same thing. In testing my knowledge I
tried the following code expecting to see the html-formatted Ring
request:

(ns test.core
(:use compojure.core, compojure.route, ring.handler.dump))

(defroutes test-routes
(GET "/test" [request] (handle-dump request))
(ANY "*" [] (not-found "Page Not Found")))

(defonce server (run-jetty #'test-routes
{:join? false
:port 8080}))

When visiting 'http://localhost:8080/test I see the html-formatted
request with all values nil. Could someone please enlighten me as to
what I'm doing wrong? I'm using clojure 1.2, compojure 0.5.3 and ring
0.2.5.

On a related note, I'd love to see an example of using middleware that
operates on the request on the way in and on the response on the way
out for the same request. I think this would go a long way to help me
understand how it's all suppose to work.

Thanks!
Tim

James Reeves

unread,
Jan 2, 2011, 3:29:10 PM1/2/11
to comp...@googlegroups.com
On 2 January 2011 17:48, Tim McIver <tmc...@verizon.net> wrote:
> When visiting 'http://localhost:8080/test I see the html-formatted
> request with all values nil.  Could someone please enlighten me as to
> what I'm doing wrong?  I'm using clojure 1.2, compojure 0.5.3 and ring
> 0.2.5.

If the binding for the route is a vector, it attempts to bind the
parameters of the request. So:

(GET "/test" [request] (handle-dump request))

Will bind the `request` symbol to a parameter named "request".

If the route is a map or a symbol, the request is bound directly. So
what you need to write is:

(GET "/test" request (handle-dump request))

Alternatively, you could write:

(GET "/test" [] handle-dump)

If you return a handler directly from the route, it will be
automatically evaluated.

Another problem with your program is that this route:

(ANY "*" [] (not-found "Page Not Found"))

Would be more correctly expressed as:

(not-found "Page Not Found")

All the functions in compojure.route return routes, rather than
response maps. As a matter of style, I tend to require rather than use
compojure.route, as:

(route/not-found "Page Not Found")

More explicitly denotes the not-found function as returning a route,
rather than a response.

I've been meaning to write up a more detailed "routes from scratch"
guide for the Compojure wiki, which I'll do after I've finished off
0.6.0.

> On a related note, I'd love to see an example of using middleware that
> operates on the request on the way in and on the response on the way
> out for the same request.  I think this would go a long way to help me
> understand how it's all suppose to work.

Something like this, perhaps?

(defn wrap-foo [handler]
(fn [request]
(let [request (assoc request :foo "foo")
response (handler request)]
(assoc-in response [:headers "X-Foo"] "foo"))))

This adds a :foo key to the request before passing it to the handler,
then adds a "X-Foo" header to the returned response.

- James

Tim McIver

unread,
Jan 2, 2011, 8:28:54 PM1/2/11
to Compojure
Thanks so much James; much more clear.

I have another question on what you mentioned about the not-found
issue. You say that you like to make explicit that not-found is
returning a route. I thought each line in defroutes WAS a route -
including the GET and other method macros - and that they returned
response maps - or nil if they don't match. I took a look at the not-
found method and was surprised to see that it does indeed return an
ANY route. I was expecting it to simply return a response map
with :body set to the passed string and :status set to 404.

Thanks again for the help. I look forward to that doc on the wiki.

Tim

James Reeves

unread,
Jan 2, 2011, 8:50:01 PM1/2/11
to comp...@googlegroups.com
On 3 January 2011 01:28, Tim McIver <tmc...@verizon.net> wrote:
> I have another question on what you mentioned about the not-found
> issue.  You say that you like to make explicit that not-found is
> returning a route.  I thought each line in defroutes WAS a route -
> including the GET and other method macros - and that they returned
> response maps - or nil if they don't match.

Assuming I've understood you, then yes, that's correct.

> I took a look at the not-
> found method and was surprised to see that it does indeed return an
> ANY route.  I was expecting it to simply return a response map
> with :body set to the passed string and :status set to 404.

If that were the case, it would be in a namespace ending in
"response", rather than "route", e.g. ring.util.response or
compojure.response.

The compojure.route namespace has functions that simplify route
creation, such as a catch-all "not-found" route.

- James

Reply all
Reply to author
Forward
0 new messages