I’ve recently been doing a lot of work with backbone.js, a JavaScript MVC framework that’s excellent for building clean applications that are backed by RESTful JSON web services. It offers a nice separation of concerns, supports your favourite JavaScript templating engine and is well-documented. What else could you need?
Well, sometimes the answer is a little bit less than what’s on offer. What about cases where you want to use just part of the framework? That’s also possible – in this case, I’m going to demonstrate how you can use backbone models to interact with your server-side code, but without the associated views and controllers.
Backbone models extend the framework’s Model class, and so you can get RESTful behaviour for free. On the server side (which, unsurprisingly, I’m using the Play! framework for), we have a couple of models:
@Entity public class User extends Model { public String userName; public String displayName; public String fullName; @OneToMany(cascade = CascadeType.ALL) public Listfriends; public static User findByUserName(String userName) { return find("byUserName", userName).first(); } // builder methods not shown }
@Entity public class Friend extends Model { @OneToOne(optional = false) public User user; public Friend(User user) { this.user = user; } }
The User class is only going to be used on the server side, but Friends will be retrieved using a RESTful service that returns JSON.
window.Friend = Backbone.Model.extend ({ urlRoot: "http://localhost:9000/api/friends", defaults: { "id": null, "user": null } }); window.FriendCollection = Backbone.Collection.extend ({ model: Friend, url: "http://localhost:9000/api/friends" });
Once client-side instances of Friend are created, calling methods such as fetch() will result in a RESTful call based on the URL given in the model declaration. To integrate this with the server side, we add entries to the routes file. In this case, we’re only going to GET all the friends of the current user, but the same principle applies to other HTTP methods such as PUT and DELETE.
GET /api/friends Friends.all
The server-side implementation is about as simple as it gets:
public class Friends extends Controller { public static void all() { User user = User.findByUserName(session.get("userName")); renderJSON(user.friends); } }
At this point, we now have everything in place to make RESTful calls and react to the asynchronous results.
<script type="text/javascript"> function showFriends() { var friends = new FriendCollection(); // Retrieve the data from the server, do something with it on a successful return friends.fetch({ success: function() { // do something with the result. All friends in the collection can be accessed by iterating over (or directly accessing) friends.models } }); } </script> Who are my <a href="javascript:showFriends()">friends</a>?
In just a few lines of code, you have smooth, clean access to your web services and a declarative model that can easily be kept in sync with your server-side models.
A complete working example can be found here. Unzip it, cd into the bbm directory, type “play run” and point your browser at http://localhost:9000.
EDIT: Please note this is written using Play 1.x. I guess I need to get in the habit of clarifying which version of Play I’m using now that Play 2.0 is nearly ready!
EDIT 2: Just to keep things even, here’s an simplified implementation in Play 2.
Great example Steve, have been trying to come up with a good way to update an existing Play Framework/jQuery website using backbone/underscore and replacing my jQuery AJAX/JSON requests this way will be a good start.