ClojureScript and Node.js Part 2 - Express


Upon discovering Node.js, the first shiny demo one typically comes across is a toy http server. It's even prominently featured on Node's "About" page. Following that, one inevitably finds Express.

We'll be showcasing the same today, but instead of JavaScript, we'll be porting the Express "Hello world" example to ClojureScript, building on a previous CLJS/Node blog post (so if you haven't read it, start there and come back when you're done).

Note: this post assumes you've followed the update at the end of the last post and switched your compilation :optimizations to :simple, as this makes running the final build artifacts easier.

Getting to "Hello world!" (again)

We'll be doing the following:

  1. Clean up unused files from last tutorial
  2. Add express NPM dependency
  3. Modify pow.core
  4. Build and run!

Simple enough!

Clean up unused files from last tutorial

We repurposed the mies lein template for our last tutorial. While this gets us up and running, there are a few files included in there that we don't need right now. Let's just remove them quickly.

$ cd path/to/pow
$ rm index.html
$ rm index_release.html

Add express npm dependency

As of writing, the latest version of express in npm is 4.11.1. Our project.clj already includes a :node-dependencies entry; just add express to that existing vector:

 ;...

  :node-dependencies [[source-map-support "0.2.8"]
                      [express "4.11.1"]]

 ;...

Pull down your new dependency:

$ lein npm install

Your project should now have a node_modules directory containing both express and source-map-support.

Modify pow.core

A word of warning in advance: Clojure and ClojureScript eschew wanton state modification whenever possible, encouraging you to use pure functions and value semantics. However, we're using a JavaScript library written without such lofty goals. Consequently, this code will not be seen as idiomatic ClojureScript. It's "functional" only in the sense that it functions, relying on hidden internal state (and changes to that state via method calls with side-effects) in order to work.

While this may seem to defeat the purpose of using ClojureScript, it underlines an important point: ClojureScript does not strong-arm you into using its conventions. Certainly, every single one of its built-in data structures and core methods will encourage this, but at the end of the day, you can drop down to what is effectively transliterated JavaScript to get the job done.

Edit src/server/pow/core.cljs thusly:

(ns pow.core
  (:require [cljs.nodejs :as node]))

(node/enable-util-print!)

(def express (node/require "express"))

(defn say-hello! [req res]
  (.send res "Hello world!"))

(defn -main []
  (let [app (express)]
    (.get app "/" say-hello!)
    (.listen app 3000 (fn []
                        (println "Server started on port 3000")))))

(set! *main-cli-fn* -main)

That's all there is. Let's attack this line-by-line.


(ns pow.core
  (:require [cljs.nodejs :as node]))

This declares your current namespace, pow.core, and requires cljs.nodejs into your current scope as node. cljs.nodejs defines namespaced references to Node's process and require globals, and defines a shortcut for delegating ClojureScript's print to Node's util.print, which we call on the next line:

(node/enable-util-print!)

Following that is a call to cljs.nodejs/require which pulls in express:

(def express (node/require "express"))

Exactly how you decide to make use of node modules will depend on the modules themselves. In this case, the express npm package exports a factory function which can be called to create new app instances. Others might export a constructor, requiring that you make new instances of it. In that case, you may choose to to create your own factory function which hides this fact, such as:

(defn make-bob []
  (let [bob (node/require "bob-mod")]
    (bob.)))

You could then (make-bob) to your heart's content. It may seem wasteful to require the module for every call, but Node caches the result of the initial module evaluation, so subsequent calls are cheap.

Moving on!


(defn say-hello! [req res]
  (.send res "Hello world!"))

Here's the crux of the program. This defines our handler, say-hello!. We bind this to the root ("/") route in -main:

  ;...
  (.get app "/" say-hello!)
  ;...

The follwing line in -main starts up the server, printing a message when it's up an running:

  (.listen app 3000 (fn []
                      (println "Server started on port 3000")))

Build and run!

From the CLI, build and run your app:

$ lein cljsbuild once server
Compiling ClojureScript.
Compiling "out/server/pow.js" from ["src/server"]...
Successfully compiled "out/server/pow.js" in 14.621 seconds.
$ node out/server/pow.js
Server started on port 3000

Crack open your browser and visit http://localhost:3000/.

END

So easy! Next, we'll take a look at the ONE-CC Stack: Om, Node, Express, ClojureScript, Cassandra. Yes, I just made that up.