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.
It seems that documentation for Clojure libraries is hard to find
on the web.
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.)
There’s a bewildering choice of
ring middlewares to try.
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))
wrap-keyword-params come with ring itself,
wrap-restful-format does content negotiation.
wrap-restful-format uses the
to decide how to interpret requests and responses. In your code you
:body to some data, and
wrap-restful-format will handle
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.
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,
put-clojure-indent can help. For example, to indent the
macro properly, use the following:
(put-clojure-indent 'GET '(:defn)) ;; ... and so on for POST etc.
(:defn) is an indent spec
which allows properly indenting even complex macros.
Another thing that often tripped me up were how comments are indented.
; comment is indented to the side.
This is the default and when using
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
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