(Todays) Adventures in Clojure

I’ve been writing a bit of Clojure again today, here are a few things I’ve learned today.

tl;dr: Look for middlewares in ring-defaults. ring-middleware-format is neat. Use cider in Emacs, and try again (and again).

Learning an ecosystem

It’s still hard to get started. I know Clojure (the language) well enough, but learning the tooling is much more difficult for me. I’ve tried to write simple APIs before, but the problems were similar each time.

Documentation

It seems that documentation for Clojure libraries is hard to find on the web. ring and compojure both have generated docs, but they are simply listings of the namespaces and the symbols in them, without top-level examples.

So what I mostly did was a combination of reading examples, glancing at the source code of different libraries (ring-defaults, compojure-api, ring-middleware-format, …), and failing to get anywhere and trying again a few days later.

(I should have been using ciders support for displaying documentation more, but that wouldn’t have helped with discovering which libraries to use.)

Middlewares?!

There’s a bewildering choice of ring middlewares to try. ring itself brings a lot of them with itself, but there are other useful ones that come from other places.

However, finding them is mostly a matter of luck, I think. I’ve started out with ring-defaults, but it doesn’t do content negotiation and too much other things.

So now it’s just the following:

(def api
  (-> handlers
      (wrap-restful-format :formats [:edn :json :yaml-in-html])
      wrap-keyword-params
      wrap-params))

Where wrap-params and wrap-keyword-params come with ring itself, and wrap-restful-format does content negotiation.

To wrap-restful-format uses the Accept and Content-Type headers to decide how to interpret requests and responses. In your code you simply set :body to some data, and wrap-restful-format will handle the conversion.

How did I learn of wrap-restful-format? I stumbled upon it while trying out compojure-api, which in turn I randomly found by searching for “compojure” on clojars.

I haven’t yet found a good way to catch errors. There are some middlewares for that, but I want one that does content-negotiation, and I don’t know if any support that.

Also, I haven’t yet found out how to selectively respond with HTML if requested, and otherwise API data. That would be very helpful for API endpoints that should also have a UI.

Neat things

This is mostly an aside, but both compojure-api and Nightlight are neat projects. With compojure-api you get automatic documentation for your API, and can even try it out there easily. Nightlight gives you an IDE in the browser. In theory that’s really cool, but it seems to be lacking for documentation support at this point.

Assorted Emacs tips

By default, the macros from compojure get indented very strangely, but put-clojure-indent can help. For example, to indent the GET macro properly, use the following:

(put-clojure-indent 'GET '(:defn))
;; ... and so on for POST etc.

Here (:defn) is an indent spec which allows properly indenting even complex macros.

Another thing that often tripped me up were how comments are indented. A single ; comment is indented to the side. This is the default and when using ;; instead the comment stays at the indentation level of the code surrounding it.

Updating the dependencies in project.clj apparently does require restarting the leiningen processes. In my case, that means rerunning lein ring server-headless and restarting the cider connection in Emacs.

Additionally, if you’ve not used cider for a while you may still have its plugin in your ~/.lein/profiles.clj file. This is not necessary anymore.