Erlang, Cowboy and Batman.js for Building Web Applications

I’ll have a complete walk of through using Cowboy and Batman.js to build the TodoMVC clone in a few days. For now I have the slides from my talk at the Chicago Erlang User Group:

Chicago Erlang User Group April, 4th 2012

I couldn’t get iframe embedding to work with WordPress… So if anyone knows what that is up with please comment.

Batman.js vs Knockout.js

The following is NOT a tutorial for either Batman.js or Knockout.js. But, it is instead a sort of side-by-side comparison of the two for creating a user creation form that POSTs the new user’s data as JSON to the backend.

The method of web development I’ve come to find the best is based on heavy frontend Javascript (though written in Coffeescript) communicating with a backend via a RESTful interface. This is appealing, because you are not cluttering the application logic with view related code. This allows me to use Erlang, my language of choice, which is great at implementing RESTful interfaces with Webmachine, but not too great for trying to build a site like you would with Rails.

I recently began using Knockout.js and found it to be a great fit for my development paradigm. When Batman.js came out, I saw that it could provide me with what Knockout.js does but also already take care of pieces I would develop myself on the frontend, like RESTful persistence.

First, we have the Knockout.js logic, written in Coffeescript, for setting up a User class and object that observers the input fields.

class @User
  constructor : ->
    firstname : ko.observable ""
    lastname : ko.observable ""
    email : ko.observable ""
    username : ko.observable ""
    password : ko.observable ""

  save : ->
    if $("form").validate().form()
      $.post('/user', ko.toJSON(this), (data) -> window.location = "/login.html"; return false ;).error () -> alert("error"); return false;

user = new User
ko.applyBindings user

Now for the HTML for displaying the fields, configuring the submit handler, binding the inputs to Knockout.js observables and setting validators.

<form data-bind="submit: save">
    <div class="new_user_box">
    <label>First Name: </label>
    <input type=text name=firstname data-bind="value: firstname" minlength=2 maxlength=25 class="required" />

    <label>Last Name: </label>
    <input type=text name=lastname data-bind="value: lastname"  minlength=2 maxlength=25 class="required" />

    <label>Username: </label>
    <input type=text name=username data-bind="value: username" remote="/user/check"  minlength=6 maxlength=25 class="required" />

    <label>Password: </label>
    <input type=password id="password1" data-bind="value: password, uniqueName: true" minlength=8 class="required password" />

    <label>Retype Password: </label>
    <input type=password data-bind="uniqueName: true"  id="password1" equalto="#password1" class="required" />

    <label>Email Address: </label>
    <input type=email name=email data-bind="value: email"  remote="/user/email_check"  class="required email" />

    <input type=submit value="Save" id="saveSubmit" />
    </div>
</form>

With Batman.js our validation will be configured in the user model. Here we only need to set @persist to Batman.RestStorage and when a model is saved with the save method it will POST the encoded fields as JSON to /users.

class CT extends Batman.App
    @global yes
    @root 'users#index'

class CT.User extends Batman.Model
    @global yes
    @persist Batman.RestStorage
    @encode 'firstname', 'lastname', 'username', 'email', 'password'
    @validate 'firstname', presence: yes, maxLength: 255
    @validate 'lastname', presence: yes, maxLength: 255
    @validate 'username', presence: yes, lengthWithin: [6,255]
    @validate 'email', presence: yes
    @validate 'password', 'passwordConfirmation', presence: yes, lengthWithin: [6,255]

class CT.UsersController extends Batman.Controller
    user: null

    index: ->
        @set 'user', new User
        return false

    create: =>
        @user.save()
        return false

CT.run()

We see below that the Batman.js HTML is a bit cleaner than that in the Knockout.js example above.

        <form data-formfor-user="controllers.users.user" data-event-submit="controllers.users.create">
          <div class="new_user_box">
          <label>First Name: </label>
          <input type=text name=firstname data-bind="user.firstname" />

          <label>Last Name: </label>
          <input type=text name=lastname data-bind="user.lastname" />

          <label>Username: </label>
          <input type=text name=username data-bind="user.username" remote="/user/check" />

          <label>Password: </label>
          <input type=password data-bind="user.password" />

          <label>Retype Password: </label>
          <input type=password data-bind="user.passwordConfirmation" />

          <label>Email Address: </label>
          <input type=email data-bind="user.email" remote="/user/email_check" />

          <input type=submit value="Save" id="saveSubmit" />
          </div>

        </form>