Caffeinated Simpleton

Second: Templates, HTTP, and JSON Parsing in Clojure

After yesterday’s introduction to the syntax of clojure, now I’m going to start organizing my code a bit more and pulling in real data.

Templating

The first thing I want to do is abstract out a base page so that I don’t need to worry about headers, JS libraries, standard CSS, and all that when going from page to page. To do this, I’ll create a “page” function in a new namespace.

(ns flockr.template
(:use compojure ))
(defn page
([title body]
(html [:html
(html [:head
(html [:title title])
]
(html [:body
(html [:div#menu "Menu"]
body)
]))
])))
view raw gistfile1.clj hosted with ❤ by GitHub

Then I add this into our original page.

(load-file "./template.clj")
(ns flockr
(:use compojure )
(:refer flockr.template))
view raw gistfile1.clj hosted with ❤ by GitHub

Now I can call the “page” function, pass it a title and some contents, and it outputs a full page. Perhaps later on we’ll make it so we can derive templates from other templates, but I have no need for that yet.

Getting My Twitter Feed

Let’s make it so that getting “/justin_tulloss” will give me my twitter feed. To do that, I add a handler to our servlet.

(GET "/:twitter-name"
(page "Your Flock"
(html [:h1 "Welcome " (route :twitter-name)])))
view raw gistfile1.clj hosted with ❤ by GitHub

Now when I go to http://localhost:8080/justin_tulloss, it will say “Welcome justin_tulloss”. Pretty high tech stuff.

Now let’s see if I can change that justin_tulloss parameter into my actual twitter data. First, I head over to the twitter API docs. The public timeline doesn’t require any authentication, so let’s pull that down first. The public timeline is a list of “status” messages, which we will map to html representations of the same. To do this, I used the clj-http-client library by Mark McGranaghan. It was a pain to get installed because I don’t understand Java JAR files fully, but once I got it figured out, it worked great.

(GET "/:twitter-name"
(page "Your Flock"
(html [:h1 "Welcome " (route :twitter-name)]
(map twitter-status
(read-json-string (let [[status headers body]
(http-get *twitter-url*)] body))))))
view raw gistfile1.clj hosted with ❤ by GitHub

Hopefully this code isn’t hard to follow, but let’s take a look. The “Welcome” part is the same. Then we map everything that we read from the twitter URL into a twitter-status function, which just grabs some data out of the statuses and displays it.

(defn twitter-status
([tweet]
(html [:p {:class "tweet"}
(html [:div {:class "tweet-text"} (get tweet "text")])
(html [:div {:class "tweet-user"} (get (get tweet "user") "name") ])])))
view raw gistfile1.clj hosted with ❤ by GitHub

Referring back to the non-templating code, the “read-json-string” function is in clojure.contrib.json.read, which you can get here. The twitter-url is a global constant. Apparently it’s a lisp thing to surround globals with asterisks. I wonder if that also applies to global constants.

(def *twitter-url* "http://twitter.com/statuses/public_timeline.json")
view raw gistfile1.clj hosted with ❤ by GitHub

Well, that’s all for tonight. Next time we’ll fetch some more relevant data from twitter and see what we can do with it. As always, the complete code is on github.