2014 was our best year yet at Firebase. We’ve grown from a community of 30,000 developers to over 130,000, introduced a static hosting service, reached one million concurrent devices connected to the Firebase servers, and joined the Google Cloud Platform team - and this is just a few of the things we’ve been up to! As we wrap up the year, we wanted to share the highlights with you and give you a preview of what’s coming in 2015.
First, however, we wanted to thank all of you. We have seen you use Firebase for incredible things this year we could not have imagined. Y Combinator, for example, is using Firebase to power its Hacker News API. Such diverse use cases pop up every week because our community of developers make Firebase a platform other developers want to use. You help each other on StackOverflow, share sample code on GitHub, and are generous with your time and feedback. We would not have come this far without you! I’m deeply grateful for your active engagement, and I speak on behalf of the rest of the team.
Technology startups are an uphill struggle, and we’ve been fortunate to reach a degree of adoption that is quite rare. You’ve helped us climb that hill and we plan to continue serving you in 2015 just as we have in past years.
Angular and Ember Support: We kicked off 2014 by attending the first ever AngularJS conference, ng-conf. We introduced Angular developers to Firebase and gave a talk on wiring up a backend for your Angular app using Firebase, which now has almost 30,000 views. A few months later we expanded our JavaScript framework support by releasing new bindings for Ember and sponsoring EmberConf.
Firebase Hosting: To provide a way for developers to build, deploy, and host their applications on Firebase, we launched Firebase Hosting in May. We were blown away by the response, and we’ve seen over 7,000 sites deployed on Firebase Hosting since it launched.
One Million Concurrents: There was quite a bit of celebration in the Firebase office when the total number of network connections to our servers reached one million for the first time. This means there are over one million users active on Firebase-powered apps at any given time.
Firebase + Google Cloud Platform: In October we joined the Google Cloud Platform team! As part of Google we’ll be able to dramatically scale Firebase and give our developers access to a powerful cloud infrastructure platform. Watch our videos from Google Cloud Platform Live to learn more.
Queries: After gathering feedback from many of you, we announced enhanced query support. Our new query features make it possible to order and retrieve data using a child key, by key name, or by priority.
Triggers: At Google Cloud Platform Live we demoed an upcoming feature that will make it easy to connect Firebase with external services. You’ll be able to use Triggers to submit a payment, send an SMS, or ping a server for logging and analytics - all without writing your own server-side code. Stay tuned for Triggers in 2015.
ng-conf and EmberConf: We’ll be at ng-conf and EmberConf in March. If you’ll be attending, stop by the Firebase booth to chat with the team and learn about our integrations with each framework.
Big things are coming in 2015. Follow us on Twitter and join our Google Group to stay up to date on the latest Firebase news. In the meantime, happy coding and have a wonderful new year!
When I started designing the tech stack for Reviewable I knew I wanted something lightweight that would allow a lone developer (me!) to put together a high quality, modern web app quickly. Most of my past experience had been with traditional client-server architectures communicating via a RESTful API, but the overhead of designing and maintaining a URL space, a complex database schema, the obligatory glue code between them on both client and server, sounded unappealing. And this is even before considering fun stuff like security, scalability, and collaboration.
As it happens I’d recently built a prototype for another project on top of Firebase and was surprised with how easy it was to work with the platform and how fast the app came together. While I initially had some qualms about whether it was mature enough to stand up to the rigors of long-term use in production, I had faith in the team and figured that shipping an MVP quickly trumped other concerns. So I decided to give it a try.
The first order of business was to set up some way to serve the app. Firebase is well-suited to a single page app (SPA) architecture, where a static bootstrap page on the client executes JavaScript to grab data from a server and renders HTML templates in the browser. Because the bootstrap page is static there's no need for a seperate application server, so all files can be served from a CDN for low latency and scalability.
I had previously tried a number of CDN solutions but never found a good combination of features and price. I saw that Firebase recently launched their integrated hosting feature with built-in support for SSL, cache control, and instantaneous file invalidation and decided to give it a try. The best part was that Firebase Hosting also supported URL path rewriting—a necessity for a modern app that uses the HTML5 History API to control the URL, while still requiring URLs to load the same static bootstrap page.
As an example, whether you visit Reviewable at https://reviewable.io or its demo code review at https://reviewable.io/reviews/Reviewable/demo/1, the same HTML page is initially sent to the browser before being populated with data from Firebase. This is easy to achieve with Firebase Hosting using a firebase.json configuration file like this:
https://reviewable.io
https://reviewable.io/reviews/Reviewable/demo/1
firebase.json
{ "firebase": "reviewable", "rules": "rules.json", "rewrites": [ {"source": "**", "destination": "/index.html"} ] }
This worked great for staging and production, but what about development? I didn't want to deploy the site to test it every time I made a small tweak, since even a few seconds' delay would disrupt the development flow. And a normal development HTTP server like python -m SimpleHTTPServer or node http-server would only serve files that directly matched the URL structure, unable to deal with path rewrites.
python -m SimpleHTTPServer
node http-server
To solve the problem, I quickly built the firebase-http-server tool that understands the configuration file and mimics how Firebase Hosting works. It's fast and dead simple to use, defaulting to reading the settings from a firebase.json file in the current directory:
npm install -g firebase-http-server firebase-http-server # load your site from http://localhost:8080
Presto, you have a running server that respects all your redirect, rewrite and header rules. The emulation isn’t perfect but it’s close enough for development work, and changes to the configuration or source files take effect instantaneously.
Another critical part of every Firebase application is writing the security rules that determine read/write access to the datastore and validate your data. Having all the rules in a central location and enforced in the datastore itself is a great idea, and much easier to deal with (and audit) compared to manual checks or annotations spread throughout your codebase. However, the native JSON format of the rules is not very human-friendly at scale, so I was looking for a solution somewhere between Firebase’s existing rules and the experimental Blaze Compiler they recently released. This inspired me to build Fireplan, an open source tool that uses a YAML syntax similar to Blaze together with Firebase’s established hierarchical rule structure.
Here's a fragment of Reviewable's actual security rules written in Fireplan syntax:
root: repositories: $ownerName: $repoName: .read: canPullRepo($ownerName, $repoName) core: connection: required oneOf('active', 'draining', 'closed') connector: userKey # null if connection closed current: openPullRequestsCount: required number && next >= 0 pullRequests: $pullRequestId: string functions: - userKey: string && isUser(next) - isUser(userKey): root.users.hasChild(userKey) - canPullRepo(owner, repo): auth.uid != null && root.users[auth.uid] != null && sanitize(root.users[auth.uid].core.public.username.val().toLowerCase()) == owner || root.queues.permissions[makePermissionKey(owner, repo, '*')].verdict.pull == true || auth.uid != null && root.queues.permissions[ makePermissionKey(owner, repo, auth.uid)].verdict.pull == true - makePermissionKey(owner, repo, uid): owner + '|' + repo + '|' + uid - sanitize(key): key.replace('\\', '\\5c').replace('.', '\\2e').replace('$', '\\24') .replace('#', '\\23').replace('[', '\\5b').replace(']', '\\5d') .replace('/', '\\2f')
Now this may look rather imposing—the function definitions in particular are pretty complex—but look at what it expands to in the native JSON format when compiled with Fireplan using fireplan rules.yaml:
fireplan rules.yaml
{ "rules": { "repositories": { "$ownerName": { "$repoName": { "core": { "connection": { ".validate": "newData.val() == 'active' || newData.val() == 'draining' || newData.val() == 'closed'", "$other": {".validate": false} }, "connector": { ".validate": "newData.isString() && root.child('users').hasChild(newData.val())", "$other": {".validate": false} }, ".validate": "newData.hasChildren(['connection'])", "$other": {".validate": false} }, "current": { "openPullRequestsCount": { ".validate": "newData.isNumber() && newData.val() >= 0", "$other": {".validate": false} }, ".validate": "newData.hasChildren(['openPullRequestsCount'])", "$other": {".validate": false} }, "pullRequests": { "$pullRequestId": { ".validate": "newData.isString()", "$other": {".validate": false} } }, ".read": "auth.uid != null && root.child('users').child(auth.uid).val() != null && root.child('users').child(auth.uid).child('core').child('public').child('username').val().toLowerCase().replace('\\\\', '\\\\5c').replace('.', '\\\\2e').replace('$', '\\\\24').replace('#', '\\\\23').replace('[', '\\\\5b').replace(']', '\\\\5d').replace('/', '\\\\2f') == $ownerName || root.child('queues').child('permissions').child($ownerName + '|' + $repoName + '|' + '*').child('verdict').child('pull').val() == true || auth.uid != null && root.child('queues').child('permissions').child($ownerName + '|' + $repoName + '|' + auth.uid).child('verdict').child('pull').val() == true", "$other": {".validate": false} } } } } }
Gotta love those quadruple backslashes! This rule complexity would be difficult to maintain in large apps like Reviewable, but luckily Firebase picked a good set of core rule semantics which made it easy to add syntactic sugar on top.
The Firebase ecosystem is still growing, but thus far I have not had occasion to regret my choice of platform. Sure it may need the occasional extra tool or library, but it’s still easy to achieve a development velocity that you could only dream of with traditional architectures.
If you have any feedback on Reviewable or any of my Firebase open source projects, I’d love to hear your thoughts. You can find me on Twitter at @reviewableio or email me at piotr@reviewable.io.
Jasko, Robert, Bjarne, Kiarokh and Rick are the team behind SurveyLegend, a platform-independent online survey web application built on AngularJS and powered by Firebase.
SurveyLegend is a company focused on reinventing online surveys. Our software enables users to create surveys with remarkable ease, both on tablets and computers. You don’t need to be a market research expert and you don’t have to deal with installing or updating any software programs. All you need is a browser and SurveyLegend’s web app.
We launched our new survey app in June 2014 to help anyone compile questions that need to be answered in an engaging way. We want to give individuals and companies the power to create mobile-friendly, gorgeous surveys comfortably - with a smile on their face. We feel no other solution in our industry has accomplished this.
With SurveyLegend you create great looking surveys on your computer or tablet wherever you are, customize the look of your survey, and display the results with eye-catching and insightful graphics - all as simple as drag and drop.
So far, the results and responses from our users have encouraged us to reinvent the market research industry through ease of use and a focus on interaction design and visuals.
Firebase is a great fit because of the realtime synchronization it provides. There are no conflicts, data which comes in later overwrites or merges with the old data seamlessly. Without Firebase, we would have to spend much more time solving synchronization issues, and optimizing and scaling our servers. Firebase enabled us to build our app more quickly and let us keep our development team small and focused on our core competence.
With Firebase, survey data is always available for respondents and their responses can always be submitted even if our servers go down. Firebase also powers our Live Analytics feature, which updates in realtime when a survey response is submitted so our users get instant feedback.
Firebase’s security rules make it easy to validate data, implement permissions and keep our users’ data safe. It saves us a lot of time and effort that would go into creating custom solutions.
On the server side, we use Linux machines running on DigitalOcean.Export of survey data is written in PHP and more real-time tasks are using NodeJS and CouchDB. We have several Node servers which act as Firebase-workers. The workers save responses and make backups of survey-data to CouchDB in real-time as well as updating Live Analytics on Firebase.
On the client-side, we develop using AngularJS and AngularFire bindings and many other libraries: Sass, Grunt and Gulp for various build tasks. We plan on moving our apps and static assets to Firebase Hosting in the future to increase the availability of our app and reduce the dependency on our own servers.
We are proud to have users from all sectors: individuals, small local businesses, global companies, nonprofit organizations, government agencies, and other institutions.
We see high school students use our solution to create small yet powerful surveys, asking challenging questions on the topic of bullying. We also see global enterprises running internal employee surveys and external customer surveys. Every day new users join from all over the world to gather much needed feedback, leading to decisive insight into their questions. Whether it’s individuals or global companies using SurveyLegend, we treat them as Legends and are proud to empower them.
We are working on two new features, Media Gallery and Custom Wallpaper. These features will not only help our users create more visually appealing surveys but will also help them create questions with images as answers.
Media Gallery is a question type guaranteed to help retail, design, and marketing companies with their choices in products, design and marketing. With the Media Gallery question type, you can ask a visual question, easily email it out or share it through social media, reaching thousands of people and leading to insightful choices for your design.
Our second feature in the pipeline is the ability to upload custom survey wallpapers. This is a feature that enables companies to further brand their survey using custom company colors or illustrations.
We have many more features on the way and we love getting feedback and feature requests, so don't be shy about contacting us. We look forward to hearing from you!