Firebase and Clojure(Script) – Part One

Overview

This blog post is part of three planned entries. They are:

  • Firebase and Clojure/Script – Part One:  Getting set up to use Firebase from Clojure and ClojureScript. It will cover adding data to Firebase and receiving changes to it in real-time.
  • Firebase and Clojure/Script – Part Two:  Leveraging Firebase’s authentication services from ClojureScript.
  • Firebase and Clojure – Part Three: Using Clojure and Firebase’s Java library to get real-time notifications of data changes.

This first one will run a bit long as I want to give a cursory explanation of the pieces used in all the posts.

To follow along make sure you:

  • have  Java 1.6 or 1.7 installed,
  • Leiningen installed (instructions for Leiningen can be found here),
  • and a Firebase Account (you can sign up here).

The Github project housing this code can be found here.

The Need

Besides being a father, a full time employee, and a soon-to-be breakout 5K weekend race star (ha!), I am trying to start a social media mining and platform business (because THAT’s not a crowded market).  Given my schedule, every moment is critical. The first items I’m trying to check off my feature list is a way for people to:

  • Log in to my service using accounts from other services such as Facebook or Twitter,
  • Capturing their email address through  a form if not provided by the service they login from,
  • Storing that information,
  • And then notifying the workers for the other features I plan to provide there is a new customer.

I wanted to find a library or service that helped expedite delivering those features while being able to use a language with which I am comfortable and productive.

The Solution

Firebase

Firebase provides the perfect vehicle for doing all of this. What is Firebase? It’s a service company focused on providing:

  • A scalable document storage which is ,
  • Accessed via a suite of provided libraries or REST API,
  • Which have notification mechanisms in place to let you know your data changes,
  • And on top of all that they help you set up authentication with Twitter, Facebook, Github, etc.

In short, they are perfect for what I need. They have both a Java library for backend work and a JavaScript library for frontend development.

Clojure and ClojureScript

The language I currently am fond of is Clojure. I find it productive and, most importantly, simple. It can run on the JVM, CLR, and via ClojureScript it can be transpiled down to JavaScript to run in the browser or on Node. This dovetails perfectly with Firebase’s JavaScript and Java libraries and will let me write in one language top to bottom. I appreciate this because I’m old and not so good with the context switching.

Chat Example

To explore adding and retrieving data from Firebase with ClojureScript, I duplicated Firebase’s short chat example. Forgive the length of what is about to follow. In case someone wanted to get started with Clojure(Script) web development, I wanted to provide enough details for them to do so.

Disclaimer: I don’t do ANYTHING pretty. So the end UI is nothing to write home (or anywhere else) about. Perhaps, Siberia or somewhere like that. Maybe.

Project Setup

Leiningen

Leiningen is the most popular dependency management tool used by Clojure developers. It sits on top of Maven and simplifies EVERYTHING to do with managing your project.  Installing it is simple and the directions are covered at the Github site. To get our project rolling, all we do is type:

This will build out your project’s directory structures and put in place some default files you will need. By including compojure after the “lein new” we had leiningen build a project customized for web applications. We’ll discuss Compojure a bit more below. The “balling-fireball” part is the name of our project.

project.clj

The project.clj is one of the files automatically created by leiningen.  It declares all of your project’s dependencies as well as clues leiningen in on all the configuration for performing compilation, “jaring”, testing, transpiling, and deploying.

:dependencies

Let’s look at the :dependencies section of the file. It specifies all the libraries used by the program to perform whatever features you build.  Each entry specifies the library and the version to include. I’ll run through real quick what each library does.

  • [org.clojure/clojure "1.5.1"] includes the Clojure language itself which is just a jar file that runs on the JVM.
  • [org.clojure/clojurescript "0.0-1909"] includes all that is needed to transpile Clojure into JavaScript.
  • [compojure "1.1.5" :exclusions [ring/ring-core]] provides Compojure which is “a small routing library for Ring that allows web applications to be composed of small, independent parts.” Ring abstracts “the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks.” If you are familiar with Ruby, Ring is the equivalent of Rack.
  • [hiccup "1.0.4"] enables the creation of HTML from Clojure data structures.
  • [domina "1.0.2-SNAPSHOT"], a ClojureScript library, provides DOM manipulation capabilities by wrapping the Google Composure library.
  • [hiccups "0.2.0"]], based on Hiccup, lets you create HTML from ClojureScript data structures.

:plugins

The plugins section tells Leiningen to include libraries that provide convenience functionality into your project. The plugins included are:

  • [lein-ring "0.8.5"]  “provides commands to start a development web server, and to turn a Ring handler into a standard war file.” Essentially, it makes it simple to run and deploy Clojure web applications. We’ll look at some of the commands below.
  • [lein-cljsbuild "0.3.3"] “makes it quick and easy to automatically compile your ClojureScript code into JavaScript whenever you modify it.”

:ring

:ring {:handler } - This section tells lein-ring what Compojure middleware and routes to use when firing up. We’ll explore the balling-firebase.handler/app below.

:cljsbuild

This section provides the plugin lein-cljsbuild all the information it needs to automate your ClojureScript development workflow.

Server Side Setup

As noted above, the server side (what little there is of it) is written in Ring and Compojure. The server side is contained in the file src/balling_firebase/handler.clj which is shown below. The goal here is to recreate the html page used by  Firebase’s short chat example.

defroutes

Let’s look at the defroutes function first. It defines three routes using Compojure’s Routing DSL which you can read more about here. They are:

  • GET “/” – Calls the (home-page) function and returns the result when a client navigates to the root of your website. There is an explanation of home-page provided below.
  • route/resources “/” – A route provided by Compojure for serving resources on the classpath. In this case, it will provide anything in the resources/public directory. The home-page discussion bellow illustrates how this works.
  • route/not-found “Not Found” - When a user asks for a route not provided by your application, this is what is delivered along with a 404 HTTP code.

home-page

Leveraging hiccup, this function generates the single html page our example needs. It’s easy to see the structure of the html code represented by the Clojure data structures. The html closely mirrors the Firebase chat example. Besides using the Clojure data structures to create the HTML, hiccup has a number of convenience methods. The three on display here are:

(def app (handler/site app-routes))

The handler/site function creates a handler which Ring uses to properly route requests. It also interjects useful middleware such as session and cookie management into the handler.

Client Side…Finally

Firebase’s chat example‘s JavaScript is embedded in the HTML. ClojureScript is not embedded because it is transpiled and the JavaScript file that is output is included via a script tag.

The syntax is very familiar after looking at the server side code, right? It’s why I love the Clojure and ClojureScript combo. I don’t have to context switch between JavaScript on my client side and whatever language I’ve written my server side in. Also, I can share business logic written in Clojure with my ClojureScript code and vice versa. It makes for a very productive development workflow.

(def messages (js/Firebase. “<your-firebase-url”))

This line initializes a Firebase reference from the URL you provide and assigns it to the messages variable.  All interactions with Firebase will use the messages variable.

init

The init function, called after the page loads, calls two functions to initialize two listeners for events from Firebase and the keyboard. We’ll examine these functions below.

init-submit-message-handler

ClojureScript uses the Google Closure compiler when it transpiles to JavaScript. The Google Closure libraries are available to you when writing ClojureScript for the browser by importing. This function uses the goog.events listen function to add an event listener for key press events. The event listener accepts a key press event, ensures that the key press was the enter key and that the event originated from the messageInput input field, and then calls the add-message function.
Note: Don’t confuse Google CloSure and CloJure. They are two very different things. CloJureScript leverages Google Closure for compilation and optimization.

add-message

The add-message function, called after an Enter key press while the focus is on the messageInput input field, calls the push method from the messages Firebase reference. The push method creates a new child location for the map containing the chat name and message in your Firebase document store and automatically assigns it a unique identifier. Firebase has a number of methods for manipulating, querying or receiving events from your Firebase document store. They can all be found in Firebase’s excellent documentation here.

The call to clj->js function before the push method converts the ClojureScript object to a JavaScript one.  ClojureScript uses a combination of native JavaScript types and Clojure data structures so when using libraries that expect a JavaScript data structure you must perform the conversion from ClojureScript to JavaScript.

This method makes use of domina which is a “jQuery inspired DOM manipulation library for ClojureScript.”  Particularly, we use the value function which returns the value of a DOM element. The great thing about  domina is that the functions are extremely easy to recall because they do exactly what they are named and unlike the Google Closure library there is no Class/Object/Method hierarchy to navigate.  We will see further uses of domina in the display-message function.

init-populate-messages-handler

This method uses the messages Firebase reference to create a Firebase Query object using the limit method which caps the number of children returned when the Firebase Document Store reports changes.  We add an event handler listening for the Query object’s “child_added” event. When a child_added event is received, the add-and-display function is called.

display-message

The display-message function takes as an argument the data changes received by the event listener set up in the initiate-populate-message-handler and converts it from a JavaScript object to a ClojureScript data structure using the js->clj method. Once that’s done, hiccups is used to construct the HTML needed to display the  newly received message(s) and then it is appended to the messages div.

It too makes use of domina.   For retrieving the messages div element, it makes use of the by-id function. For appending to the message-div, it makes use of the append! function. Again, domina is great because things are named simply  and you don’t have to navigate Class/Object/Method hierarchies to get things done.

Run It!

Fire It Up

lein cljsbuild auto

To access our application, we first need to transpile our ClojureScript to JavaScript. In the terminal at the root of your project, type the following:

Once it starts, you should see something similar to the below:

This uses the cljs-build plugin above to begin a process that monitors the directory where you write your ClojureScript and, upon a change to a file, transpile it automatically and place it in the proper directory to make it available to your application. All of the configuration information needed by cljs-build is specified in the project.clj file discussed above.

lein ring server-headless

Now we need to use the lein-ring file specified in project.clj’s plugin section to start the application.

This fires up Jetty, plugs your server-side code into it, and then listens on port 3000.

Use It

Point a browser to http://localhost:3000 and you will see your application and now all you have to do is use it. As promised, it ain’t pretty. Put your name in the first input box, a message in the second, and push enter. You’ll see your message appear above the two input boxes. Check your Firebase datastore on the Firebase store and see how your message was stored. Open a second browser tab pointed to your application and enter a message there and watch it appear in the other tab pointing to your application. For such a minimum amount of code, you get data storage and real-time coordination of data changes. It’s why Firebase is an incredibly handy service.

Wrap Up

In this post we saw how to:

  • install leiningen,
  • run leiningen,
  • configure leiningen,
  • write the necessary Clojure server side code for our chat application,
  • and then write our ClojureScript client side code to interact with Firebase.

Next post will build on this work to allow people to log in to our chat service using accounts from other services such as Facebook or Twitter.  It will also be nowhere near as long.

Comments

  1. Hi

    just fyi – I’ve added this blog to Planet Clojure, so all posts tagged as ‘clojure’ will be syndicated there…

    thank you

Trackbacks

  1. […] Firebase and Clojure(Script) – Part One:  Getting set up to use Firebase from Clojure and Clo… […]

Follow

Get every new post delivered to your Inbox.

Join 662 other followers

%d bloggers like this: