Easy Clojure Web Development

Clojure is a great language, the parens can be tamed with tooling like parinfer and the dynamism can be harnessed with joker and spec. If you haven’t given it a shot, you should whenever (if ever) you get some free time away from the day to day.

Web development

That’s not really what this post is about though. This post is about clojure web development. How do you make great web apps with clojure? As is customary in ecosystems where libraries take precedence over frameworks, you have a proliferation of great options for web development. Multiple http servers, multiple http abstractions, multiple multiples. When I was first starting out in the clojure world with an eye towards web development, I wasn’t just overwhelmed, I was flabbergasted. I literally went back in time and thought of an old, crazy word to describe the situation. I vowed after I got familiar with clojure and it’s rich history of web frameworks to make my own. And I did: coast.

A short, subjective take on clojure web frameworks

There are quite a few clojure web frameworks and things that behave like frameworks if you check out the /r/clojure subreddit. Here are a few of them:

Noir

This one is near and dear to my heart. I’ve never used it to build anything but the API is one of the cleanest I’ve seen for interacting with a database and separating html fragments into components. The downsides are that it’s not really maintained anymore and it relies on macros when functions would do just fine.

Clams

This one is similar to coast and was really kind of where coast started, it uses alliteration just like ruby on rails, and coast on clojure. It is glue code that holds a bunch of disparate libraries together. It looks pretty good! One of the downsides is that it uses leiningen which without a trampoline makes things quite a bit slower and more complex. Another thing is that gluing libraries together is great, but it would be nice to not have to deal with each library authors idiosyncrasies and differing versions of dependent libraries.

Fulcro

This one is pretty crazy and goes above and beyond what coast can currently do. It apparently unifies a clojurescript frontend with a clojure backend to create client heavy and server heavy application. You’ve really moved up the abstraction hierarchy when you use this architectural masterpiece.

Hoplon

This is another one that does appear to be simple but below this apparent simplicity lies another full stack framework for single page apps. Which is great! If you need or want single page apps, hoplon and fulcro have you covered like a peanut butter jelly sandwich.

Luminus

Now we’re getting into competitor territory. Luminus is almost like a framework, it’s a collection of libraries that more or less work together. Luminus is a really great place to start with clojure web development, all of the pieces are already put together and it definitely makes things easier on newcomers.

Pedestal

This is more for APIs but I definitely like their approach to routing and the interceptors are a nice change from the confusion that is ring middleware.

That brings us to Coast

I’ve been working on coast along with a small group of people, they mostly just gave their input on how they were confused when I did something stupid, but I’m very, very grateful for every chat we’ve had and every issue filed and every WTF moment they suffered through.

Coast recently got a slew of new features, some long standing annoying bugs were fixed and a whole bunch of new documentation was written. Let’s dive in

The main thing that really makes coast stand out from other clojure web frameworks is the integration. Other frameworks are mostly a conglomeration of existing libraries, but coast has a lot more coast specific code that all sort of fits well together. Here’s an example, database migrations, database relationships and pull queries.

Database Migrations

Instead of use an existing database migration library like ragtime or migratus, coast uses its own migration code which allows migration syntax that looks more like ruby on rails than plain SQL (the preference of everyone in clojure land apparently):

; db/migrations/20190926190239_create_table_author.clj

(ns migrations.20190926190239-create-table-author
  (:require [coast.db.migrations :refer :all]))

(defn change []
  (create-table :author
    (text :email :null false)
    (text :screen-name :null false) 
    (text :password :null false)
    (text :photo)
    (timestamps)))

; db/migrations/20190926190240_create_table_post.clj

(ns migrations.20190926190240-create-table-post
  (:require [coast.db.migrations :refer :all]))

(defn change []
  (create-table :post
    (text :title)
    (text :body)
    (references :member)
    (timestamps))

Associations

Normally in an object oriented web framework like rails or django, you have models which are classes that represent your database tables, and the relationships between them. In coast there are no classes, no objects and no models, just data. So how do we define the relationships between tables to make it easy to query like an ORM? Associations.

(ns associations
  (:require [coast.db.associations :refer [table belongs-to has-many tables]]))

(defn associations []
  (tables
    (table :author
      (has-many :posts))

    (table :post
      (belongs-to :author))))

Pull Syntax

If there are no models, no classes and no objects, how do we query the database without just using plain old sql? Pull syntax is the answer. Ripped straight from datomic’s readme, pull syntax is a boon to productivity and clarity when it comes to querying relational sql databases:

(pull '[author/screen-name
            {:author/posts [post/title :post/body]}]
          [:author/id 1]))

There are a lot of other examples where coast has turned into its own full stack framework instead of a mishmash of existing libraries that weren’t necessarily made to fit together.

I’ll get into the nitty gritty of why you should try coast out instead of sticking with your web framework du jour in the next post, stay tuned 📺