Home > clojure > A Brief Note on Compojure Routes and Requests

A Brief Note on Compojure Routes and Requests

November 3rd, 2010 Leave a comment Go to comments

This post is mostly for my own reference, but hopefully someone else will find it helpful. I’ve been playing with Compojure and, maybe because it’s a young framework, have found up-to-date documentation and examples hard to come by. I think this is exacerbated by the fact that Compojure was broken up (I think) into Ring, Clout, Hiccup etc.

Note that I’m using Compojure 0.5.2. Hopefully this info applies to future versions.

Anyway, the problem I had, which seemed really simple, was getting query parameters from the request in route rules. In a lot of ways, my reptillian, Java-poisoned brain was overthinking the issue. Once I stepped back and thought about it, here are the simple rules that became clear to me:

  • The second argument to the GET macro (or POST, etc) is a binding form. If you give it just a symbol, you’ll get the entire request map (see below)
  • The request binding form can use destructuring to pull out the parts of the request map you need.
  • If an entry in defroutes table returns nil for any reason (say you’re just trying to print a query parameter, but you have a typo), Compojure moves on and tries the next entry.

That’s it. I know, I know … dumb, but coming from languages with syntax and lots of “special forms”, it’s easy to let Clojure trick you into thinking there’s more to something than there really is.

Finally, and the real reason for this post, is “What does the request map actually look like, so I know what I can destructure from it?!?”. Here’s a dump of the request map I made once the lightbulb came on:


{
  :body               #<Input org.mortbay.jetty.HttpParser$Input@3e1d25>
  :character-encoding nil, 
  :content-length     nil, 
  :content-type       nil, 
  :cookies            {}, 
  :form-params        {},
  :params             {"word" "bar"}, 
  :query-params       {"word" "bar"},
  :query-string       "word=bar",
  :remote-addr        0:0:0:0:0:0:0:1,
  :request-method     :get,
  :route-params       {},
  :scheme             :http,
  :server-name        "localhost", 
  :uri                "/foo", 
  :server-port        8080, 
  :headers {
    accept          text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8, 
    accept-charset  ISO-8859-1,utf-8;q=0.7,*;q=0.7, 
    accept-encoding gzip,deflate, 
    accept-language en-us,en;q=0.5, 
    connection      keep-alive, 
    host            localhost:8080
    keep-alive      300, 
    user-agent      Mozilla/5.0 ...,
  }, 
}

One thing to note is that the keys of :params and :query-params are Strings, not keywords!

Destructure away.

Categories: clojure Tags: ,
  1. Patrik Hedman
    November 4th, 2010 at 04:31 | #1

    Just thought it deserved a mention that if you wrap the keyword-params middleware that comes with ring it will turn those string keys into keywords.

  2. November 4th, 2010 at 07:49 | #2

    @Patrik Hedman
    Thanks. So something like (run-jetty (wrap-keyword-params my-routes) {:port 8080} ) would convert params to keywords? Looks like I need to spend some time with the Ring source.

  3. Patrik Hedman
    November 4th, 2010 at 08:36 | #3

    @dave
    Yes, that would do it.

  1. No trackbacks yet.