Clojure + Boot Backend For The React.js Tutorial

Last weekend I worked my way through the introductory tutorial for React.js. It’s very well written and easy to follow, I was really happy with it overall.

For the uninitiated, React.js is a framework that provides a means to create reusable javascript components that emit HTML in a very intuitive way. Taking that concept a step further, its possible to use React on the backend, utilizing the same components to build the UI that is served to the user initially. The end result is very interesting. React prescribes an intuitive and scalable approach to building complex, dynamic user interfaces as highly reusable components.

These user interfaces avoid the redundancy of generating and manipulating HTML twice – once on the server, and again in the browser.

The server-side rendering feels like a natural pattern in a Node.js environment, but there are examples in the wild of doing server-side rendering with other platforms, most notably clojure. This is exciting stuff.

React has been around for a while, but this is the first time I’ve taken a close look at it.

The tutorial focuses on building a simple font-end application rendered entirely in the browser. Initially, you work with a standalone HTML page, and near the end, you integrate it with a simple web application.

The source repository for the tutorial provides some example applications written in Python, Ruby and Node.js.

A simple application like this seemed like an ideal use case for a simple boot script, so I decided to write one of my own. Here’s the code inline, but I’ve forked the repository if you’d like to examine the code along-side its cohorts.

#!/usr/bin/env boot
 
(set-env! 
  :dependencies 
  #(into % '[[org.clojure/data.json "0.2.5"]
             [ring/ring-core "1.3.2"]
             [ring/ring-jetty-adapter "1.3.2"]]))

(require '[ring.adapter.jetty     :as jetty]
         '[clojure.data.json      :as json]
         '[ring.middleware.params :refer [wrap-params]]
         '[ring.util.response     :refer [file-response response]])

(defn static
  [request]
  "Handle static file delivery"
  (let [uri (:uri request)
        path (str "./public" uri)]
    (if (= uri "/comments.json")
      (file-response "./_comments.json")
      (file-response path))))

(defn save-comments
  [request]
  "Save the comments to the json file, and return the new data"
  (let [data (json/read-str (slurp "./_comments.json"))
        input (:form-params request)
        out (concat data [input])
        new-json (json/write-str out)]
    (spit "./_comments.json" new-json)
    (response new-json)))

(defn handler
  [request]
  "Simple handler that delegates based on the request type"
  (case (:request-method request)
    :post (save-comments request)
    :get (static request)))

(def app
  "Add middleware to the main handler"
  (wrap-params handler))

(defn -main
  [& args]
  (jetty/run-jetty app {:port 3000}))

Essentially, it sets up two handlers, and then a dispatcher that proxies between them depending on the type of request. If the request is a GET, a static file is assumed. This serves the html and any local dependencies. If the request is specifically for comments.json, the handler serves the _comments.json file.

If the request is a POST, its assumed that the body of the request contains a JSON-encoded comment to add. It deserializes that data and the _comments.json file, and appends the new comment to the list. The result is then saved to the filesystem.

Obviously, there is little in the way of error checking going on here. This tracks with the scope of the other example applications.

Note: It’s not clear to me exactly why they used _comments.json to store the data – in my initial prototype I named it comments.json and placed it with the other static files.

Interestingly, this boot script also serves as a minimalistic example of a web application using ring – including adding middleware.

This was a fun way to finish up a really informative tutorial – I’m excited to continue exploring what React.js can do, especially with Clojure!

Special thanks to alandipert and ul from #hoplon for code review and some great advice on cleaning up my initial implementation!

Advertisements
This entry was posted in boot, clojure, devleopment, tutorials and tagged , , , , . Bookmark the permalink.

One Response to Clojure + Boot Backend For The React.js Tutorial

  1. Pingback: Links & Reads from 2015 Week 6 | Martin's Weekly Curations

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s