119 Labs LLC

Ideas on Technology

Hello World With Compojure & Leiningen

Compojure is a web framework for clojure. It is built on top of ring and provides a good starting point for web based clojure apps. It is not a direct replacement for a stateful web app framework like rails or spring webflow. Instead it allows you to quickly connect clojure code to the web and is ideal for building backend systems which can communicate over http. It took me a bit of working around since compojure 0.4.0 came out to get it to work with a simple hello world project. Thanks to the incanter folks for getting me most of the way there.  First off if you’re working (or just playing) with clojure then leiningen is really a must.  It using a combination of maven & ant to manage dependancies and build your projects. First you can get started by installing lein using the instructions on their website. Installing lein Next from the command line make a new project: lein new helloworld Cd into your new project directory and take a look around. The main files we’ll be dealing with are project.clj and the src directory.  Open up the project.clj file. It should look something like this:
(defproject helloworld "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [
      [org.clojure/clojure "1.1.0"]
      [org.clojure/clojure-contrib "1.1.0"]
])
If you’ve worked with Maven before this should look pretty familiar . First thing we need to do is add a couple of dependancies. Edit the file so it looks like the following:
(defproject helloworld "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.1.0"]
[compojure "0.4.0"]
[ring/ring "0.2.3"]])
First we’ve added a dependency on compojure version 0.4.0 second we’ve included a dependency on all the jars in the ring project. By default compojure includes a dependency on ring for the essentials, but it leaves out the adapters (including the jetty adapter) which we’ll need to complete a live demo.
Next we need to create a clojure file that describes our web application. Under the src directory create a file called simple_web_app.clj. Put the following code in that file:
(ns simple_web_app
(:gen-class)
(:use compojure.core, ring.adapter.jetty)
(:require [compojure.route :as route]))

(defroutes webservice
(GET "/" [] "<h1>Hello World</h1>")
(route/not-found "<h1>Page not found</h1>"))
(defn -main [& args]
(run-jetty webservice {:port 8080})
)
Lets take one block at a time:
(ns simple_web_app
(:gen-class)
(:use compojure.core, ring.adapter.jetty)
(:require [compojure.route :as route]))
This block sets the namespace to be simple_web_app, includes some required classes, and tells the compiler to create a java class file for this set of functions. Next
(defroutes webservice
(GET "/" [] "<h1>Hello World</h1>")
(route/not-found "<h1>Page not found</h1>"))
This block defines a set of routes called webservice. We have two routes here. The homepage should return “Hello World” while all other pages should return “Page not found”. Last section
(defn -main [& args]
(run-jetty webservice {:port 8080})
)
This creates a main method for the generated class. As part of the main method it starts a jetty instance and passes in our defined routes as the application to run.
One last step. Now that we have a clojure file which contains our webapp, we need to tell lein to package the jar so this class is run. This is by done by adding the following to the project.clj:
:main simple_web_app
Making the final project.clj look like this;
(defproject helloworld "1.0.0-SNAPSHOT"
:description "FIXME: write"
:dependencies [[org.clojure/clojure "1.1.0"]
[org.clojure/clojure-contrib "1.1.0"]
[compojure "0.4.0"]
[ring/ring "0.2.3"]]
:main simple_web_app)
Now out at the command prompt run
lein deps
lein compile
lein  uberjar
java -jar helloworld-standalone.jar