Up and Running with Clojure

Posted on by in Development

For the last three years or so, Clojure has been a language that I admired from afar: the design of the language is wonderful but I’ve never really used it to build anything and haven’t looked closely at the language in a while. Recently we had a Carbon Five tech showdown between Node.js and Ruby to see which system could pump out “Hello World” as fast and as consistently as possible. Since then we’ve added a Go version that impressed us a lot.

But we’re missing a JVM-based entry which gives me a great excuse to dive into the Clojure world and learn how things work.

Getting Started

Step 1 is to create a new project for our codebase. I installed Leiningen and ran:

    lein new hellod

which creates our project structure along with placeholders for necessary files. We’ll add dependencies to our project.clj file as necessary, similar to a Gemfile in the Ruby world, including Clojure itself. Clojure is just a library for the Java VM so lein will download it like any other dependency. You should already have the JVM installed on your machine.

The Code

Now we need to implement our server in src/hellod/core.clj. Clojure doesn’t come with a simple HTTP server in its core libraries. We’ll use Aleph, which provides a simple HTTP server API on top of Java’s well-regarded Netty library.

In fact, Aleph has essentially the exact Hello World server we need to implement as an example in its README. Cut and paste for great victory!

(ns hellod.core)
(use 'lamina.core 'aleph.http)

(defn hello-world [channel request]
  (enqueue channel
    {:status 200
     :headers {"content-type" "text/html"}
     :body "</pre><h1>Hello World</h1><pre>"}))

(defn -main [& args]
  (start-http-server hello-world {:port 8083}))

Now we run the project:

    lein run

and execute ab against our server:

    ab -n 10000 -c 50 http://127.0.0.1:8083/

You can see the results for several different languages and runtimes.

We didn’t do a lot of coding in this blog post but we solved half of the problem with new environments: get something working. Now that we have a basic skeleton working, we can start learning new language features and libraries as we add functionality.