A Simple Link Shortener in Clojure

01 June 2015

Recently I took it upon myself to dive into clojure. This post describes what my reaction was after writing a link shortener service using it. For those only interested in the code, check out my github.

I've always wanted to learn a lisp. I played with Scheme, Common Lisp, but never really dug deeply into it. Now knowing python extremely well, I wanted to try and scope an application reasonably and write it in Clojure. For the unitiated, Clojure is a lisp written on the JVM.

In Clojure's own words:

Clojure is a dynamic programming language that targets the Java Virtual Machine (and the CLR, and JavaScript). It is designed to be a general-purpose language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language - it compiles directly to JVM bytecode, yet remains completely dynamic. Every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.

I had recently learned Java and figured that this would be a good way to branch out on the JVM. The application I decided to write was a link shortener - it's a well scoped problem and touches a lot of interesting things that you'll encounter working full time in the language. I forced a couple of requirements, I wanted to jar it and be able to deploy it, I wanted it to connect to Redis in order to store shortened links, and I wanted to make sure that I could deploy it withDocker. Lastly I wanted to make sure that I wrote tests as well.

What I love about the link shortener application is that you're going to run into plenty of little challenges writing the application.

You'll touch on:

  • The documentation for the language itself
  • The build tools
  • Web app frameworks in the language
  • Simple regular expressions in the language (url validation)
  • HTML templating
  • Testing

Now this isn't something that will take very long assuming you have basic programming skill and if you're looking for more of a challenge there are tons of ways to add onto this application. One of the requirements is that code and tutorials are not to be followed - I made myself write it from scratch.

Now there aren't a lot of resources on the web that teach you how to write Clojure. However there were a couple of websites that really came in handy. Brave Clojure was great as is Aphyr's post on Clojure. And of course the Clojure docs. I leveraged their how to write a webapp in clojure as a rough guide but wasn't doing any copying and pasting.

There were a couple of things that blew me away about Clojure. Firstly it felt extremely natural, all functions are nice and short and I love polish notation. The regex wasn't too bad (although I had to jump into some javadocs to understand limitations/capabilities) either.

What took me a bit of getting used to psycologically was immutable data structures, which I'm now enamored with. Initially I couldn't figure out the use case, but as I thought about it more, it makes a lot of sense. You make better design decisions and it makes things so much more predictable.

Leiningen was also awesome. It's a great build too and made things super easy to work with.

Hiccup is honestly one of the most awesome libraries I've used. It was unbelievably easy to write composable functions that generated HTML so simply. It made writing functions easy and really Clojure really stands out in readability. Once you get past the parens everywhere, it really lends itself to quick understanding.

For example:

(defn shorten
  [params]
  (let
    [link (params :link) possible-link (controllers/set-link link)]
    (if (false? possible-link)
      (gen-shorten-failure link)
      (gen-shorten-success link possible-link))))

We have to shorten our params, we'll let the link = the link from the input parameters and the possible link be what we get back from our controller. If we get null/false value generate our failure, if not generate success.

I really loved that I got to avoid html almost completely and didn't have to use some templating engine. All I really want is an HTML generator anyways.

If you're interested in deploying, you can download the repository and build and run it yourself. The only requirement is a Redis container which you can get from Docker Registry.

Then you just have to run.

docker run --name new-red redis
docker run --name clj --link new-red:new-red -p 5000:5000 -d my-cloj

Navigate to your Docker url on port 5000 and you should be good!

Check out my other post on writing a link shortener in Scala.