0 to Clojure in less than 10 lines of code

One of my New Year’s Resolutions this year was to learn a functional programming language. After much deliberation, I decided to start with Clojure/ClojureScript, mostly because of the latter’s great interoperability with JavaScript. Fast forward a few months, and I’ve become a little obsessed with this language — it has the elegance of Ruby, the power of Java, and the reach of JavaScript.

Clojure, however, seems to be a loaded word these days. Take this conversation I had the other day while discussing plans for my next (and first) billion dollar startup:

Obviously the front end will be a GUI written in Visual Basic

People hear Clojure, and seem to associate it with difficult, or complicated. I know, because I was one of those people too! All those parentheses? Running on the JVM? Preferred editor is Emacs? And did I mention the parentheses? There is no way I could read, write, and let alone enjoy this witchcraft! However, after just a few weeks of using Clojure, the parenthesis, JVM, and Emacs colt started to disappear. I started realizing Clojure is arguably the simplest language of this century, not to mention one of the most expressive.

However, I didn’t reach that decision overnight. While there are some great options to learn Clojure in depth, I often found myself not knowing where to start. I had learned the syntax and the general principles, but had no way to practice them, short of using a large, intimidating template. For me, that was the most frustrating part of learning Clojure — so today I’ll walk you through how to write a self-contained Clojure web server in less than 10 lines of code (without golfing!). Ready? Let’s go!

I’ve added a couple new lines to break it up by section. Take them out though, and it’s 9 lines of code!

Before we get started, we’ll need to install two things: boot-clj and Java 8. Boot is going to be what we use to run our Clojure code, and Java is going to be the platform that our code runs on. If you have a Mac, it’s as easy as:

brew update
brew tap caskroom/cask
brew install boot-clj Caskroom/cask/java
#! /usr/bin/env boot

The first line is a shebang, which tells the computer how to execute the file. We’ll indicate that we should use boot to run the file.

Clojure files typically use the extension .clj, and need to be snake_cased, so we’ll call this file zero_to_clojure.clj. Be sure to give it executable permissions! (chmod +x zero_to_clojure.clj)

(set-env! :dependencies '[[compojure "1.5.0"]
[http-kit "2.1.8"]])

Boot handles everything you need to build a Clojure app, including handling dependencies. We can update our build environment with a function boot provides called set-env!. Here we just add some dependencies, including the version numbers we want, and boot will handle everything else for us. It will search for them (they’ll most often be found on clojars.org), download them, and put them in the right place. Think of it like dynamically adding gems, or npm packages.

We’re going to need 2 packages:

compojure: Compojure is a routing library — similar to Sinatra in Ruby, or Express in JavaScript. It’s very expressive, and gives you a lot of control over your routes.

http-kit: Httpkit is the web server — it plays the same role that WEBrick and thin do in Ruby, and that Node’s http package does in JavaScript. It describes itself as being minimalist, efficient, and highly concurrent.

The single quote preceding the packages, aptly called a quote character, is very common in Clojure (or any lisp). Think of it like an escape character — it tells Clojure not to run the code immediately after it, but to instead return exactly what you write. You don’t have to worry about it for this exercise, just be aware that it’s there, and that it’s important!

(require '[compojure.core :refer [defroutes GET]])
(require '[org.httpkit.server :refer [run-server]])

Boot is going to download the packages for us, but their functions aren’t loaded in the global namespace. We’re going to need to require a few functions to use. We’ll use the function require, passing it what we want to require, and which functions we want to use in our current namespace. The two lines above give us the ability to run 3 functions: defroutes, GET, and run-server.

You can require other verbs from compojure and use them the same way as GET: POST, DELETE, PATCH, etc.

(defroutes routes
(GET "/" [] "Hello World!"))

We’re going to use two of those functions now — defroutes and GET. We’ll define a set of routes with the function defroutes — it accepts a name, and an unlimited number of route handlers. A route handler looks like this:

(VERB "/pathname" [arguments] <return value>)

Here, we’ll use GET, to define a route at the root, that just returns the string “Hello World!”.

(run-server routes {:port 9001})

Let’s fire up that server! We required the function run-server from http-kit, so all we’ll have to do is pass it our route handler and specify a port to start the server on. This will start up a server and return the server instance.

We pass in the port as part of a hash-map, defined with curly braces. Typically you’ll use a symbol as a key (which, just like Ruby, start with a colon).

(boot (wait))

Without this line, if we were to run our code, it would exit as soon as the server starts. We want it to stay alive until we tell it to stop, so we have to tell boot to wait for our instructions. This is built into boot, so you don’t have to install any extra dependencies.

Let’s run the code!

By now your Clojure file should look like this:

Go into the console, and run your very first Clojure web server! Disregard the warnings for now, jump into your browser, and visit localhost:9001. You should see something like the following:

Quick, add Clojure to your LinkedIn!

As you can see, Clojure is very expressive, and can be very easy to get up and running with. We were able to create a stand alone file that boots up a highly concurrent web server with expressive routing in less than 10 lines of code.

It should be noted that just as you don’t write your entire Ruby or JavaScript app in a single, executable file, you normally don’t inline everything in a single file in Clojure. 😉

To really understand what’s going on with the code, you’ll have to play around with it. Go ahead and add more routes, functions, logging, whatever you want! To get you started, here’s a more verbose example: