TL;DR: Check out this chat example, featuring authentication, message persistence, and username storage, done in ~ 100 LOC (most of which is simply view logic!):
This chat application was developed using my own Firebase adapter for Ember Data. The source is available on GitHub (and if you're not familar with the Rails app structure, the Ember app itself lives here).
Firebase is one of the most impressive technologies I've had the pleasure of using in the past few months. It's a hierarchial data store-as-a-service built to be the back-end for web and iOS applications. While I usually don't like to hitch a wagon to a back-end I don't control, I was impressed enough by Firebase that I decided to give it a shot.
What I found was that the real power lied not in the storage back-end itself, but in Firebase's JavaScript API. Rather than simply acting as an interface for REST requests via AJAX, Firebase's Javascript API offers events for when items are added, changed, and removed, powered by a persistent WebSocket connection.
Immediately, I saw the potential that Firebase had when used as a back-end for Ember. By adapting Firebase for use with Ember's data persistence library, Ember Data, I could create models and queries that could update in real time, and require no extra boilerplate to handle add and remove events.
The chat app is a bit of a cliche example of real-time applications at this point, but it's a good starting point. This one also shows off a few of the advantages of Firebase: it uses Firebase's authentication API to keep track of users, and all messages are stored within a Firebase reference for later viewing.
Let's step through it, file by file.
Before diving into the program flow, take a look at the models themselves:
Note that the models extend DS.Firebase.Model
, not the standard DS.Model
class.
The store is created like any other Ember Data store, with the current API revision and an adapter instance:
The dbName
property is the subdomain of your Firebase.
Here's what this schema will look like on the backend, once persisted:
The router here is the only entry point into the application. Anyone can see the chat without logging in, so we go ahead and load all of the current chat messages with a .find()
call to that resource.
This is where the Firebase magic happens: any find()
call with no argument is interpreted as a live-updating resource. This find call will not only find all of the current messages (stored in /messages/<id>
), but will also update automatically when new messages are added or when messages are removed.
The chatController
the router creates is simple, mainly handling new messages:
You'll notice, though, that it also synthesizes the singleton AuthController
with the needs
property. This controller handles authorizing users through Firebase's Simple Login API:
This is a little messy, but essentially does the following steps:
AuthController
instance is created by the ChatController
, it creates a FirebaseAuthClient
to see if the user is currently authorized.authed
is equal to false). Logging in with this button will open a Persona login prompt, which will attempt a login when completed./users/<auth id>
resource that has a set nickname.hasName
will be set to true, and the view will display the message entry prompt. If not, the view will instead display a prompt asking for a name. This prompt will call the pickName
method, which will save the name back to the server.Finally, the views that display everything are relatively simple. Here's the single template for the entire application:
Messages are iterated over just as you would any other controller's content. Again, though, new messages will be automatically added to the controller's content, and thus the template will update as new messages are posted.
The bottom InputView
has a bit of code to facilitate picking names and sending messages, but is pretty much self-explanatory:
And that wraps up the code involved. There's a few other files in the repo, but nothing else with any real content to it.
This is a really simple example, and only shows off a tiny subset of what Firebase and Ember Data can do. Firebase doesn't stop at the cliched chat example - it can handle the complexity real-world usage has.
The adapter supports both the features you'd expect from a real-time backend as well as the normal features of a REST backend. You can have models that update live as their Firebase object changes, powerful relationships, and even live-updating relationships, all with zero boilerplate for handling changes.
Discuss this post on Hacker News.