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!
Six months ago we released Firebase Hosting! We’ve been amazed by the apps you’ve deployed and we’re excited to see many more to come. Since the launch, our hosting service has had 99.99% uptime and we've seen nearly 6,000 websites deployed a total of 100,000 times. These sites have uploaded more than 700 GB of HTML, CSS, JavaScript, image data, and more to their websites, and many of them are using Firebase to host their own custom domains - including Pathwright and Thinkster.io. If you haven’t tried Firebase Hosting yet, you can dive right in by watching our screencast or checking out the five minute quickstart.
After getting feedback from developers using Firebase Hosting in development and production, I want to share some hints on using the hosting tools effectively.
A common question we see is how to manage different environments with hosting. To start, I’d recommend creating a separate Firebase for each environment (i.e. my-app-dev, my-app-staging, my-app-prod). With our Hacker Plan you can create up to ten free Firebases, and creating multiple Firebases allows you to test things like rewrite rules and redirects before deploying to production. If you have a deploy script, you can easily switch out the name of your Firebase in your app to match your current environment. Only Firebases with a custom domain need to be on a paid plan for Firebase Hosting.
The firebase-tools repo is constantly being improved and a lot of the features explained here have been added since v1.0.0. If you’re on an older version make sure you’ve updated to the latest by running:
npm update -g firebase-tools
You can just as easily run Firebase tools from a script as you would from the command line. Here are a few hints that might make things a little easier:
-s
--email
--password
~/.firebaserc
firebase
--firebase
firebase deploy
Many of you have requested support for uploading user-generated content like images and files in hosting, and improved SEO support in single page apps. Thank you for your feedback - these features are definitely on our roadmap.
We’re always looking for more ways to improve hosting and we’d love to hear what you think. Share your feedback or show us an app you’ve deployed with hosting in our Google Group or mention @Firebase on Twitter.
Yesterday we were at Google Cloud Platform Live in San Francisco. We had a great time introducing developers to Firebase through our booth and two presentations.
Things got started with the keynote, where there were several great new Cloud Platform products announced, including Google Container Engine (GKE) and Google Cloud Interconnect.
Here’s the video from my section of the keynote, where I announce a brand new Firebase feature -- richer querying in Firebase.
Later in the day my co-founder, Andrew, led a session that demonstrated how to create an iOS app with Firebase and built it live on stage in Swift! You can watch his talk and the live coding awesomeness here:
Throughout the day, the Firebase team chatted with developers at our booth and demoed cross-platform apps powered by Firebase. We’ll be open-sourcing our furniture app, Executive Mover 5000, soon, so stay tuned for details.
We’re thrilled to be part of the Cloud Platform team, and over the next few months we’ll be working on new Firebase features as well as integrations with many of Cloud Platform’s services. Thank you to everyone who came to the event and watched on the live stream.
Today we're launching enhanced query support across our iOS, Android, and Web clients, and the Firebase REST API! You can now query your data by any child key in Firebase. Querying has been a frequently requested feature and we’ve made great strides based on developer feedback since our beta release last month.
This release dramatically improves the way you can query your data in Firebase. With our new querying methods you can order and retrieve your data using a child key, by key name, or by priority. Our existing priorities-based ordering will continue to work, but I encourage you to try out the new queries features as it is much more flexible.
A basic Firebase query starts with one of our orderBy functions: orderByChild(), orderByKey() or orderByPriority(). You can then combine these with five other methods to conduct complex queries: limitToFirst(), limitToLast(), startAt(), endAt(), and equalTo(). Since all of us at Firebase agree that dinosaurs are pretty cool, we’ll use this sample firebase of dinosaur facts to demonstrate how you can write complex, realtime queries. To start, we can use orderByChild() to retrieve dinosaurs ordered by height:
orderByChild()
orderByKey()
orderByPriority()
limitToFirst()
limitToLast()
startAt()
endAt()
equalTo()
var ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); ref.orderByChild("height").on("child_added", function(snapshot) { console.log(snapshot.key() + " was " + snapshot.val().height + " meters tall"); });
Firebase *ref = [[Firebase alloc] initWithUrl:@"https://dinosaur-facts.firebaseio.com/dinosaurs"]; [[ref queryOrderedByChild:@"height"] observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@ was %@ meters tall", snapshot.key, snapshot.value[@"height"]); }];
Firebase ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); Query queryRef = ref.orderByChild("height"); postsQuery.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot snapshot, String previousChild) { System.out.println(snapshot.getKey() + " was " + snapshot.getValue().get("height") + " meters tall"); } // .... });
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"'
var ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); ref.orderByChild("weight").limitToLast(2).on("child_added", function(snapshot) { console.log(snapshot.key()); });
Firebase *ref = [[Firebase alloc] initWithUrl:@"https://dinosaur-facts.firebaseio.com/dinosaurs"]; [[[ref queryOrderedByChild:@"weight"] queryLimitedToLast:2] observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.key); }];
Firebase ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); Query queryRef = ref.orderByChild("weight").limitToLast(2); queryRef.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot snapshot, String previousChild) { System.out.println(snapshot.getKey()); } // .... });
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="weight"&limitToLast=2'
var ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); ref.orderByChild("height").startAt(3).on("child_added", function(snapshot) { console.log(snapshot.key()) });
Firebase *ref = [[Firebase alloc] initWithUrl:@"https://dinosaur-facts.firebaseio.com/dinosaurs"]; [[[ref queryOrderedByChild:@"height"] queryStartingAt:@3] observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) { NSLog(@"%@", snapshot.key); }];
Firebase ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs"); Query queryRef = ref.orderByChild("height").startAt(3); queryRef.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot snapshot, String previousChild) { System.out.println(snapshot.getKey()); } // .... });
curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3'
The best part is that all these queries will update in realtime as the data changes in your Firebase. There’s more I haven’t covered, so be sure to read the documentation for the iOS, Android or Web clients or the REST API to learn about all the new features.
With querying, we’re also introducing a new indexOn rule type to the Firebase Security and Rules language. You can use indexOn to tell your Firebase which child keys your app uses in queries. A node's key and and priority are indexed automatically, so there is no need to index them explicitly. Using indexOn is optional and can be left off for prototyping, but it will dramatically improve performance so you'll want to add it once you've figured out the indexes your queries will use.
While this represents a big step forward in terms of our querying capabilities it also lays the groundwork for even more improvements. We have a number of exciting features in the pipeline for our SDKs, including more queries improvements. And as always, we'd welcome your feedback on what you'd like to see next.
Let us know what you think in our Google Group or on Twitter, and send any suggestions to firebase-support@google.com.
Over the past three years, we’ve gone from a crazy idea that ‘just might work’ to a proven product used by 110,000 developers. Today, I couldn’t be happier to announce that we’ve joined Google.
Two big reasons.
First, Google’s backing allows us to dramatically scale Firebase. We’re proud of what we’ve built over the last three years, but we’ve only scratched the surface of the opportunity ahead of us. With Google’s engineering talent, resources, and technical infrastructure, we’ll be able to do much more, much faster.
Second, our products and missions are highly complementary. Both the Firebase and Google Cloud Platform teams come to work each day for the same reason: to help developers create extraordinary experiences. By joining forces, Firebase developers will gain access to a powerful cloud infrastructure suite, and Cloud Platform customers will gain access to our rapid development capabilities. Together we’ll deliver a complete platform for mobile and web apps.
Firebase is here to stay and grow. You can continue to count on the same great development experience, tools, libraries and community commitment that have become synonymous with Firebase. If you’re a developer who has built an app on top of Firebase, nothing will change for you, and you can continue to use Firebase as you normally would. We’ll continue to be platform agnostic and provide clients for iOS, Android, the web, and more.
To our developer community, thank you. Building Firebase has been a challenge and you’ve helped immensely with your encouragement and support. Thank you for your API feedback, answering StackOverflow questions, submitting pull requests to our open source projects, and building your apps on Firebase. Many of you have bet your startups and careers on us -- we’re constantly humbled by this and look forward to serving you for many years to come.
You can read Google’s announcement here. Also, we'll be sharing more at Google Cloud Platform Live on November 4th in San Francisco. We'd love for you to join us in person to meet our team and learn about the great things we're working on. If you can't make it, don't worry - everything will be streamed live.
Finally, if you’d like to come and help us write the next chapter of Firebase, we’re hiring.
Happy coding,
James TamplinCo-Founder & CEO
With the fall hackathon season underway, we’ve had a chance to introduce a ton of talented college students to Firebase. We continue to be amazed by the hacks students are building in just a few hours (with barely any sleep!).
Last month we participated in MHacks, where students used Firebase to build things like “collaborative graffiti via text” and “real world Pokemon”. At CalHacks this past weekend, the best hardware hack used Firebase for a shirt that tracks your posture in realtime. See below for a recap of our favorite Firebase hacks from MHacks and CalHacks.
Abe, Chris, Joey and Mike from Firebase traveled to Ann Arbor, Michigan to support 1,100+ hackers from across the country at MHacks. At the end of the hackathon, 34 teams used Firebase to store and sync their app’s data in realtime. These were the Firebase top two:
Our top prize went to VoteApp, a web based voting platform where users can create a new poll and display the results in realtime. Designed to replace an expensive and specialized device currently used for voting in class, these four students wanted to build a universal and free solution. Use it to run your next classroom poll, it’ll be the easiest one you’ve ever done!
Our second place prize went to City Paint, which aims to reduce the prevalence of graffiti in urban areas by creating an online graffiti wall. These virtual walls can be placed around cities, and residents can text ASCII art to the wall and watch as their tags are added in realtime.
Over half of the Firebase team had the opportunity to meet the 1,000+ hackers at the amazing Cal Memorial Stadium last weekend. We had a great time helping hackers, and were impressed by their uses of the Firebase API. Both winners of our prize connected hardware to Firebase for realtime IoT awesomeness.
The Nextile Shurt team built a device with flex sensors and accelerometers that ran on two Intel Edison boards. It captured motion data in realtime and displayed the data on a web app. The best part? They attached their device to a shirt, so that when you move the degree of motion is stored in Firebase. It can be used to track posture or for physical therapy.
Our second place prize went to the Pomsafe team. Pomsafe is a home security and automation platform running from a Texas Instruments LaunchPad, powered by Firebase. When the device is attached to a door, it monitors temperature in realtime and reports when the door is opened to detect possible break-ins.
We're always excited to see what students build with Firebase in such a short amount of time, and we can't wait for the next hackathon! Follow us @Firebase on Twitter to find out which hackathons we'll be attending next.
“In addition to giving developers near real-time access to our data, we got out of the box well designed, easy to use SDKs for iOS, Android and the Web, in addition to a REST API for developers building server apps. It should hopefully making switching your apps fairly painless.”
var ref = new Firebase("https://hacker-news.firebaseio.com/v0/"); var itemRef; ref.child('topstories').child(0).on('value', function(snapshot) { if(itemRef) { itemRef.off(); } //Get the ID of the top article var id = snapshot.val(); //Get the article details and update in realtime itemRef = ref.child('item').child(id); itemRef.on('value', function(snapshot) { var item = snapshot.val(); document.getElementById("score").innerHTML = item.score; var anchor = document.getElementById("article_a") anchor.innerHTML = item.title; anchor.href = item.url; document.getElementById("comments_a").href = "https://news.ycombinator.com/item?id=" + item.id; }); });
Firebase *ref = [[Firebase alloc] initWithUrl:@"https://hacker-news.firebaseio.com/v0/"]; __block Firebase *itemRef = nil; Firebase *topStories = [ref childByAppendingPath:@"topstories"]; Firebase *firstStory = [topStories childByAppendingPath:@"0"]; FirebaseHandle handle = [firstStory observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) { if(itemRef != nil) { [itemRef removeObserverWithHandle: handle]; } NSString *itemId = [NSString stringWithFormat:@"item/%@",snapshot.value]; itemRef = [ref childByAppendingPath:itemId]; [itemRef observeEventType:FEventTypeValue withBlock:^(FDataSnapshot *itemSnap) { NSLog(@"%@", itemSnap.value); }]; }];
final Firebase ref = new Firebase("https://hacker-news.firebaseio.com/v0/"); final Map<Long, ValueEventListener> valueEventListenerMap = new HashMap(); ref.child("topstories").child("0").addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { if(!valueEventListenerMap.isEmpty()) { for(Long id : valueEventListenerMap.keySet()) { ref.child("item").child(String.valueOf(id)).removeEventListener(valueEventListenerMap.get(id)); } valueEventListenerMap.clear(); } //Get the ID of the top article Long id = (Long) snapshot.getValue(); //Get the article details and update in realtime ValueEventListener articleListener = ref.child("item").child(String.valueOf(id)).addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { Map itemMap = (Map) snapshot.getValue(); // Print the title to the console System.out.println(itemMap.get("title")); } @Override public void onCancelled(FirebaseError firebaseError) { } }); valueEventListenerMap.put(id, articleListener); } @Override public void onCancelled(FirebaseError firebaseError) { } });
Check out the full HN documentation at hacker-news.firebaseapp.com.
With more than 100,000 developers using our platform, we’ve seen Firebase used both as the entire backend for apps as well as to power specific realtime features in apps. A growing use case has been loading data into Firebase to expose an API to other developers. Traditionally, building and maintaining a public API is a big undertaking; often entire teams are dedicated to it. It’s not easy to give third party developers access to your data in a way that’s both safe for your users and powerful for those developers. With Firebase, all you need to do is sync data to your Firebase and API consumers can then use one of Firebase’s realtime clients or the REST API to consume that data. You don’t have to worry about scaling with developer usage and or documenting anything beyond your data structure. You can learn more in a blog post we published last year.
We can’t wait to see what you build!
Last week, we released v1.0.0 of our open-source apps Firepad and Firechat! These are two great open-source modules built on top of Firebase that you can take and use in your own apps.
Firepad is a collaborative text editor. It lets you bring the features of Google Docs right into your app. Firepad can handle both code and rich text, and is currently being used in production by Atlassian, LiveMinutes, and CoderPad to name a few.
Firechat is a realtime chat app built with Firebase. Firechat’s features include multi-user / multi-room chat, flexible authentication, moderation, presence, private messaging, chat invitations and more. CBS is using Firebase to power the realtime chat for their Big Brother TV series.
Orginally we built both of these modules to showcase the realtime and collaborative power of Firebase, but they’ve grown into full-featured, production-ready pieces of functionality. Both projects have reached the point where they’re stable, full-featured and well-documented, so we’ve decided to officially tag them as 1.0!
Here's what's new in the 1.0.0 releases:
With help from the community, we’ve added some highly-requested features and fixed many bugs over the past few months.
We added a headless mode for interacting with documents programmatically with no GUI (e.g. from your backend server code). It can run in Node or in a browser. To use it from Node, just run npm install firepad, require the module, and add a headless instance of Firepad using the following code:
npm install firepad
var Firepad = require('firepad'); var headless = new Firepad.Headless('');
We've made a number of API improvements to make writing apps using Firepad easier. For instance, there's a new defaultText option to specify initial text to be loaded in Firepad, and there's a new "synced" event to notify you when your changes have successfully been synced with Firebase so you can provide notice to the user. See the API docs for full details.
defaultText
We've also fixed many minor bugs and UI issues to make the collaborative editing as fluid and seamless as possible! Firepad is now available on the Firebase CDN as well as Bower, making it even easier to include in your app.
Our Firechat homepage is now hosted on Firebase Hosting. In addition to this, we’ve improved the documentation, fixed bugs, and added warning messages to make development easier. Firechat now works well with other frameworks like Twitter Bootstrap, so you can customize the app’s default styling.
If you’re using Firepad or Firechat in your apps, we’d love your input. Email us any feedback at firebase-support@google.com or submit a pull request on GitHub. We’re excited to see what you build!
Ever since we released GeoFire for JavaScript, we've seen many requests for mobile ports of the library. Today, we're happy to announce GeoFire for iOS and Android!
GeoFire is now supported on our three major platforms - web, iOS and Android - and each library is open source! Each version comes with a sample app, which queries and displays San Francisco public transportation data in realtime.
You can find the corresponding sample apps as part of the GeoFire repos for Objective-C and Java.
If you're new to GeoFire, it's a geolocation library that maps string keys to locations and stores them in Firebase. Using GeoFire, you can answer a simple but important question: Which keys lie within a given geographic region? But GeoFire's features don't stop at simple location queries, it's true power is that everything happens in realtime. When objects move, events will be fired as they enter, exit and move around the region.
GeoFire opens a wide range of possibilities: You can build an app that displays who's going for a run within a mile radius of yourself and show their location in realtime. You can display taxis within a search radius and animate them as they move. Or you can build an app that simply lists all interesting bars nearby.
The GeoFire libraries are available as a XCode Framework and as a Java jar-file for easy integration. Add them to your app, include the Firebase library and you're ready to go.
All three versions are compatible with each other. If you are storing locations in your iOS or Android app, you will be able to query them in the web and vice versa.
Take a look at our quick start guides for the Objective-C and the Java versions to get familiar with GeoFire on each platform.
GeoFire is designed to be a lightweight add-on for Firebase, not a replacement. As such, you will continue to store your data just as you would normally do in Firebase and use GeoFire to query keys by location.
Let's assume we're building a social running app, where we want to display stats for all runners in our area. We'll start by storing basic data for each user like the following:
{ "users": { "steve123": { "displayname": "Steve T.", "age": 29, "location": [37.12314, -122.49182], "stats": { "averageSpeed": 11.2, "currentSpeed": 9.7, ... } }, "nikky_kay": { "displayname": "Nicole", "age": 37, "location": [37.67134, -122.32990], "stats": { ... } }, ... } }
Now that we've stored our user information in Firebase, we'll use GeoFire to search for nearby runners in realtime. In this example, we're storing each user by their username, and the user's location as a pair of latitude-longitude coordinates. By keeping the location key as a child of the user key, we can listen for realtime updates for a single user. Everytime we update the location of a user we simultaneously update the location for that user in GeoFire.
We'll now use a GeoQuery to retrieve all keys (usernames in this example) in a given geographic region. Using the key entered and key exited events, we can keep track of all users currently matching the query, e.g. with a NSMutableSet in Objective-C or Set<String> in Java.
NSMutableSet
Set<String>
NSMutableSet *runnersNearby = [NSMutableSet set]; // query around current user location with 1.6km radius GFQuery *query = [self.geoFire queryAtLocation:currentUserLocation withRadius:1.6]; [query observeEventType:GFEventTypeKeyEntered withBlock:^(NSString *username, CLLocation *location) { [runnersNearby addObject:username]; // additional code, like displaying a pin on the map // and adding Firebase listeners for this user }]; [query observeEventType:GFEventTypeKeyExited withBlock:^(NSString *username, CLLocation *location) { [runnersNearby removeObject:username] // additional code, like removing a pin from the map // and removing any Firebase listener for this user }];
final Set<String> runnersNearby = new HashSet<String>(); // query around current user location with 1.6km radius GeoQuery geoQuery = geoFire.queryAtLocation(currentUserLocation, 1.6); geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() { @Override public void onKeyEntered(String username, GeoLocation location) { runnersNearby.add(username); // additional code, like displaying a pin on the map // and adding Firebase listeners for this user } @Override public void onKeyExited(String username) { runnersNearby.remove(username); // additional code, like removing a pin from the map // and removing any Firebase listener for this user } ... });
We're ready to update our UI in realtime! Now that we know which users are nearby and we want to display, we can add a normal Firebase listener to each user and keep their stats updated in realtime. Remember, adding a listener in Firebase is a very lightweight operation, and adding thousands of listeners is not a problem. If a user ever moves outside the query, all we need to do is remove that listener and update our UI.
We're excited to see the amazing apps you build with Firebase and GeoFire! If you have any feedback on our new mobile libraries, you can email me at jonny@firebase.com or send us a pull request.
This past weekend Y Combinator hosted a hackathon, YCHacks. 540 developers answered the call. Over the weekend they turned pizza, energy drinks, and APIs into 123 projects.
At Firebase we really love hackathons, so it didn't take much effort to convince about half of the team to attend. This gave us a great opportunity to exchange high fives with developers who use Firebase. It turned out to be quite a few high fives because 34 teams used Firebase including two of the top three prize winners. In fact, so many developers used Firebase, that nearly 4% of the total network traffic was to our API servers.
All of the presentations were impressive, but a couple stood out as the best realtime apps.
Awear combines the Myo gesture detection arm band with Bluetooth location beacons to provide you with a way to control the technology near you by waving your hand. For example, when you're in the living room, a hand gesture might turn on the music, and in the kitchen the same gesture could flip through a digital cookbook.
Awear is a great example of how ubiquitous Internet connectivity is going to change the way devices talk to each other. With so many devices interacting with each other, the team found inter-device communication challenging. At 3:00 AM on Saturday they decided to give Firebase a go. Within a couple hours, all of the hardware was working in harmony. To quote them, "Firebase, you saved our lives!"
Virtual reality makes a lot of new, amazing experiences possible, but the Vrniture team also thinks it can change the way we do some more mundane tasks. Specifically, shopping for furniture. Vrniture used Firebase to wire up 3d models of your room with models of furniture you might like. It then presented a preview on an Oculus Rift so that you can experience new furniture in your home without having to rent a truck.
Those were our favorite examples of realtime development with Firebase, but there was other cool stuff too. A lot of it happened to be powered by Firebase.
High fives keep many of us running. They're an effective way to smack back the things that get us down. But as effective as they are for happiness, they're hard to track. It's hard to know if you've had your prescribed dose.
Quantified High Fives changes all that. It uses the motion sensor in the Pebble smartwatch, and a Firebase to accurately and effectively track your intake of High-5s. It even displays your current count in realtime. Now when you wonder, "Have I had enough?" your Pebble smartwatch and Firebase can tell you.
Tanay Tandon of team Athelas added a hemispherical lens to an iPhone and discovered that the optically enhanced camera was able to image individual blood cells. He then threw OpenCV at in an attempt to identify blood borne pathogens, like Malaria. In other words, he turned commodity electronics into a low cost blood scanner. The scanner app then stores test results in Firebase.
YCHacks was great fun. We really enjoyed seeing all of the ways that people used Firebase, and we can't wait for the next one!
There was some celebration in our office yesterday as the total number of concurrent network connections to our servers topped one million for the first time. This is a much bigger milestone than simply one million total users; it means that at this very moment there are one million users active on Firebase-powered apps.
Firebase is no longer the scrappy little startup you might remember from our launch more than two years ago. We’ve grown up. More than 83,000 developers have created over 100,000 applications using our platform. Our servers handle 24,000,000 user sessions every day, and in the last month we’ve seen traffic from over 50,000,000 unique IP addresses (over 1% of the IPv4 address space!). Our customer list now includes large companies like Google, Yahoo, and Citrix, as well as up-and-coming startups like Instacart, Nitrous.io, and Invision.
Our team has grown as well. One year ago, there were seven of us. Today, there are 24 (plus an intern), including new folks hailing from great companies like Google, Microsoft, and Salesforce. We’ve even welcomed our first PhD to the team.
The last couple years have been a whirlwind, but we’re far more excited about what’s coming next. Nearly every part of our product has new features currently under heavy development. In fact, most of the work we’ve done over the last year has been on features that have yet to be announced. Expect big upgrades to our core API, mobile support, security API, tooling, educational resources, and framework integrations in the near future.
Mobile is an especially bright spot for us. Our sync-based API is especially powerful on mobile devices where network connections are spotty or absent. As a result, Android and iOS are now our fastest growing platforms, and we’re putting a ton of resources into improving our mobile featureset.
None of this would have been possible without a ton of community support. Thank you for your help, whether that was providing API feedback, contributing to our open source projects, answering questions on our Google Groups, or simply telling a friend about our service.
We’d invite you all by our office so we could thank you in-person, but we know most of you are not in San Francisco. So instead, if you’d like us to send you some delicious Firebase Hot Sauce and other swag, shoot us an email and we’ll hook you up. Or, if you are in fact in San Francisco, you’re welcome to come by for office hours any Friday.
Thanks again, and we look forward to updating you again at 10,000,000 concurrents!
Greg and Mark are the Co-Founders of Pathwright, an online education platform built with Firebase and hosted on Firebase Hosting.
Pathwright is a platform for online education that allows anyone to teach and sell online courses under their own name and brand.
Education is something that is easy for us to get excited about. Most of our team is comprised of former or current professional educators. Drawing from past experiences, we saw a great opportunity to fix some of the problems we saw with online learning.
Most software developed for education has been designed to supplement classroom use, not to deliver a full education online. Additionally, the user experience for teachers and students is often very poor. We started Pathwright to give forward thinking teachers an easier, more attractive way to share knowledge online.
The most heavily trafficked system being powered by Firebase is our notification system. It allows us to notify students and teachers about important events that are happening in real time.
Secondly, we use Firebase to host our Pathwright.com marketing website. We previously hosted our website on Amazon S3 behind CloudFront, but the cost of using our pathwright.com SSL certificate with CloudFront was significant in comparison to Firebase.
Given that we are a small team, making use of Firebase has saved time and money from a development and operational standpoint. We have been able to continue working on our core platform instead of hassling with the additional infrastructure.
The automatic provisioning of SSL certificates was a time-saver, and a great value. Additionally the documentation was simple, and the whole process took about ten minutes from start to finish.
Since we were a very early adopter, we contacted support to ask about a feature that we didn’t see available yet. Firebase support responded quickly and helped us get a workaround in place within 24 hours, allowing us to re-launch with Firebase almost immediately. Customer service was fast, friendly, and thorough.
Firebase Hosting has been great for us and our customers. We recommend it without hesitation.
On the server side we’re running on Amazon Web Services. Some of the more critical pieces of our stack include Linux, Postgres, Python, Django.
On the client side we develop in CoffeeScript, Sass, and Backbone.js with Marionette.
We have a variety of customers covering a wide range of topics on Pathwright. Some of our favorites include Integral Calc, GetElected and Ligonier Connect.
GeoFire is an open-source JavaScript library that allows you to store and query a set of items based on their geographic location. GeoFire uses Firebase for data storage, allowing query results to be updated in realtime as they change. GeoFire does more than just measure the distance between locations; it selectively loads only the data near certain locations, keeping your applications light and responsive, even with extremely large datasets.
To showcase the power and simplicity of GeoFire, we built a demo which uses it alongside our Firebase Transit Open Data Set. The demo allows you to drag a circle around San Francisco and see all MUNI (the public transit system for the city) vehicles which are currently within it. Since GeoFire is built on top of Firebase, the demo updates in realtime as you drag around the circle and as new data comes in.
The GeoFire data for this demo is stored in a public Firebase which is freely available for use by any developer. We also provide GeoFire data for our latest open data set, launching today, Parking.
In addition to the MUNI demo, we created several other examples which show you how to perform common tasks in GeoFire. The code for all examples, including the MUNI demo, is available in the GeoFire GitHub repository.
A growing number of apps and websites - from car-sharing services to food recommendation apps to local event aggregators - alert users to places or things near them. While server-based solutions for geolocation queries are nothing new, there was nothing which allowed you to do them efficiently in Firebase. So we introduced GeoFire last September to provide you with an easy way to do client-side, on-the-fly filtering of geolocation data.
GeoFire 2.0 is a complete rewrite of that GeoFire library. We simplified the API and aligned it closer to the Firebase JavaScript client API you are already familiar with. You can now do even more with smaller, cleaner code. This version of GeoFire is now "production ready" - we have improved performance, added several common feature requests, and are ensuring its quality with a comprehensive test suite.
The best way to see what GeoFire can do is to jump right into the code. GeoFire has dependencies on Firebase (for realtime data storage) and RSVP (for an implementation of JavaScript promises), so we need to include them in our HTML file along with the GeoFire library:
<head> <!-- RSVP --> <script src="path/to/rsvp.min.js"></script> <!-- Firebase --> <script src="https://cdn.firebase.com/js/client/1.0.17/firebase.js"></script> <!-- GeoFire --> <script src="https://cdn.firebase.com/libs/geofire/2.0.0/geofire.min.js"></script> </head>
The necessary files are also available via Bower and npm. See the GeoFire documentation for full download instructions.
GeoFire stores its data at whatever Firebase location you choose to pass it:
var firebaseRef = new Firebase("https://<your-app>.firebaseio.com/geofire/"); var geoFire = new GeoFire(firebaseRef);
Once you have created a GeoFire instance, you can add locations to it using set(). It takes as input a unique, arbitrary key to represent the location as well as the location's latitude-longitude pair:
set()
geoFire.set("some_key", [37.785326, -122.405696]).then(function() { console.log("Provided key has been added to GeoFire"); }, function(error) { console.log("Error: " + error); });
To retrieve the location of a key at any time, pass the key to get():
get()
geoFire.get("some_key").then(function(location) { if (location === null) { console.log("Provided key is not in GeoFire"); } else { console.log("Provided key has a location of " + location); } }, function(error) { console.log("Error: " + error); });
GeoFire's real utility is shown by creating a GeoQuery. Say you are making an app for cyclists which shows the bicycle shops within a mile (1.609 kilometers) of a user's current location. The first thing you need to do is add the bike shops you care about to GeoFire. Then, create a query centered at the user's current location (let's say they are at [37.4, -122.6]):
GeoQuery
[37.4, -122.6]
var geoQuery = geoFire.query({ center: [37.4, -122.6], radius: 1.609 //kilometers });
A query on its own is not very useful. However, GeoFire allows you to add callback functions which are fired when important query events happen. Since you want to display every bike shop which matches the query criteria, listen for the key_entered event. Every time a key (that is, a bike shop) enters the query, the callback you defined will get called with data about that location:
key_entered
geoQuery.on("key_entered", function(key, location, distance) { console.log("Bicycle shop " + key + " found at " + location + " (" + distance + " km away)"); });
It is important to realize that the key_entered event works like typical Firebase events. That is, it will be fired for every key in GeoFire which matches the query criteria, both keys which are already in GeoFire and those which are added at any point in the future. Thanks to Firebase, you receive these events in realtime.
GeoFire is smart about how it looks for keys within the query. It does not need to load all of the GeoFire data into memory. If your user is looking for bicycle shops in San Francisco, GeoFire will not load data for locations in New York only to realize that they are on the opposite side of the country. It only checks on locations which are actually nearby. This keeps your app light and responsive, regardless of how big your data set is.
If your user is biking around while looking for a shop to visit, it is possible that shops which were within a mile of them are now further away. To deal with this, GeoFire will fire the key_exited event for each key which leaves the query:
key_exited
geoQuery.on("key_exited", function(key, location, distance) { console.log("Bicycle shop " + key + " left query to " + location + " (" + distance + " km away)"); });
That is really all you need to make your app work. GeoFire offers other features not covered here, including:
To learn more about these features, read the full documentation and view the code samples.
GeoFire 2.0 is available today and is ready to be integrated into your website or app. If you have any questions or feedback, post them in our Firebase Google Group or reach out to us on Twitter. We cannot wait to see what you build with GeoFire!
Cy is the Founder of Crowdsound, a realtime audience engagement tool built with Firebase and Angular.
Crowdsound is a one-stop shop for live events.
Whether you’re creating a talk, a panel, a seminar, a news show, or any live event, you can interact with your audience in real time. Crowdsound allows you to look at your audience’s demographics, take questions from audience members, quickly poll them, and follow up with them later.
On top of that, Crowdsound gives those audience members a say in the conversation. They become more than just users: they become participants. They can even message each other to stay in touch after the event is over. No more fumbling to to exchange contact info.
It began with trying to get feedback on a talk of ours. While we were trying to solve this problem, we realized that there was a bigger issue at hand. How could we get active participation from an audience? The problem became clearer when the event got broadcasted live to a virtual audience.
Right now, most events are like one-way streets: you simply deliver content to passive viewers and listeners. We were inspired by the idea of finally giving audience members active voices in the conversation, regardless of where they’re located.
The first time I witnessed a speaker answer my question during a livestream was exhilarating. I felt included in the event and immediately invited more of my friends. We want more people to feel exhilarated--to feel like they’re being heard. We want to enable large groups of people to share their ideas and collaborate to reach their goals. That’s what motivates us at Crowdsound.
Because of the real-time nature of our app, we built it completely on Firebase and Angular. We are truly putting Firebase’s capabilities to the test.
It was clear we needed a tool to send live data changes to thousands of devices simultaneously. Without Firebase, we would’ve needed a much bigger team, and that team would’ve taken months to build what we’ve built in just a couple of weeks.
In addition to AngularFire we’re using a custom implementation of Kato Richardson’s synchronized array.
We have a Node server on Heroku and static assets on Amazon S3. The great thing about Firebase (and its Security and Firebase Rules) is that it gives us a centralized place to exchange data. That way, we can use Firebase as an API to our own servers and make more complex queries. It’s especially useful when we need to crunch analytics information for our customers.
Professors using Crowdsound to quiz their students in real time. It's great to see them quickly getting a pulse on how well their students are absorbing the material.
In a classroom setting, we’re deterred from speaking up when we don't understand a concept because we don’t want our peers to think we’re not as smart as they are. It’s human nature. Unfortunately, what often happens is that half the class doesn’t understand something, but no one actually wants to speak up. Crowdsound lets teachers test their students anonymously on the fly and use the results to focus on the concepts that actually need extra attention.
We’re excited to share that native video streaming and private rooms are coming very soon. After witnessing our customers fidgeting with Google Hangouts that only allow 10 users and other streaming services that take forever to set up, we wanted to create a one-stop solution with everything you need to run your live event out of the box.
Today we’re excited to launch Firebase Hosting, production-grade hosting for developers. Firebase Hosting is designed for use by mission-critical sites and apps. We’ve built it from the ground up for security, reliability, and scale.
No other hosting service matches these features.
On top of this, we’ve made Hosting incredibly simple to use by providing one-command deploy and one-click rollback. Developers now have a fast, secure, and reliable way to host their apps.
Once upon a time, in the dark ages of the internet, apps dynamically generated HTML server-side every time a page was requested. This was slow, difficult to scale, and required users to connect to distant servers to get their content.
Even worse, this required clients to talk to a server on every state transition. For mobile users, this meant applications would break the moment connectivity was lost.
With the advent of fast JavaScript engines and powerful mobile devices, client-side page generation has become common. Angular, Ember, React, and a number of other client-side rendering technologies have transformed the application stack. Servers no longer need to send different HTML to each client. Instead, a single optimized set of static assets can be served to all clients. These static assets can then be placed on a geographically-distributed CDN, meaning users need only load data from a nearby point-of-presence (POP) rather than a server on the other side of the planet.
This new model has advantages for both end users and developers:
Faster Load Times: Static assets are cacheable and can be served from a local CDN POP.
Smoother State Transitions: Apps no longer need to load HTML from servers to move from page to page.
Apps Work Offline: Application logic runs on the device, meaning apps remain responsive even without network connectivity.
Easier to Scale: Delivering static content is easier than scaling server processes.
Less Complex Operations: Fewer servers to worry about means you can spend more time writing code.
Better Cross-Platform Support: Since all dynamic data is loaded from an API, it’s easier to build for mobile, web, IoT, etc.
Static apps load dynamic, personalized data from an API. Firebase is a popular choice for this API since we eliminate the need for server-side code and allow apps to deliver data changes in realtime. We’ve been thrilled to be a part of this shift and are especially excited about the popularity of our bindings for Angular, Ember, Backbone, and React.
However, providing only an API for dynamic data left our developers needing to find their own solution for hosting their assets: HTML, JavaScript, images, etc.
You, our developer community, voiced your frustration with existing hosting solutions. None of them had the same level of ease, reliability, and polish as the Firebase API. Since hosting is such an integral part of app development, we chose to solve the problem ourselves.
It means we've thought hard about how hosting should work. Firebase Hosting includes:
1. One-command deploys; one-click rollbacks
Deploy your content in seconds with the Firebase command line interface. Once uploaded, content begins serving immediately. With one click in the App Dashboard you can rollback to an earlier version and it will begin serving immediately. There’s no need to re-upload an old version if you’ve made a mistake, saving you precious time.
2. SSL by default
Every app on Firebase Hosting is served over HTTPS. Gone is the pain and expense of buying and installing an SSL certificate. From acquiring the cert to securing your domain, we do it all for you.
3. Your own domain
If you have a paid account, you can serve content from any custom domain, even a naked domain. Using our free plan? Don’t worry, you’ll get all the other advantages of Firebase Hosting on your own firebaseapp.com subdomain, for free!
4. Lightning fast content delivery
With Firebase Hosting you get a global footprint out of the box. We’re using one of the fastest CDNs available. Content is cached at POPs in North America, Europe, and Asia Pacific on SSDs, meaning no matter where your users are, they get your content fast.
5. Straight-forward pricing
We’re rolling Firebase Hosting into our existing plans, without raising the price! If you’re on our free Hacker plan you get:
Firebase Hosting is available starting today. Over 1,000 apps and sites have been deployed in our beta period and we're using it to host Firebase.com!
Get started by signing up. For more details, check out the documentation.
Welcome to the future of hosting!
Chris RaynorFirebase Hosting Lead
In our last blog post, we discussed best practices for using arrays in Firebase. If you haven't read that, please start there. This blog post will discuss advanced concepts for converting between real-time objects and sortable, filterable arrays.
Okay, so let's get some working gloves on and start handling synchronized arrays. If we want client-side sorting, filtering, and other things arrays are great at, but also need the awesome collaborative aspects of real-time objects, then we're going to be up to our elbows in code. We're going to work in JavaScript here, because that's what I'm most familiar with. All of these techniques can be translated to iOS and Android as well.
Before we get started, it's worth mentioning that there are some great frameworks that have already resolved the problems we face with synchronized arrays. In fact, we'll be drawing from the principles of their array management throughout this article.
EmberFire provides array handling out of the box, integrating Firebase neatly into the Ember.js framework. If you're already a glowing Ember dev, check out the Ember + Firebase Guide for details.
AngularFire version 0.8.0 provides utilities for using arrays in Angular. If you are an ngDev, Check out the Angular + Firebase Guide for details.
BackboneFire provides similar capabilities for those osteologists who prefer Backbone's flexible MVVM.
Drawing from the lessons learned in developing libraries like AngularFire, we can lay down a solid set of principles to keep ourselves out of trouble:
In other words, our array is essentially a one-directional loop. Changes come from the server into the array, we read them out, we push our local edits to the server, they trickle back into the array.
Okay, let's get started handling synchronized arrays in Firebase.
Let's start simple:
function getSynchronizedArray(firebaseRef) { var list = []; // put some magic here return list; }
This provides a method we can pass a firebaseRef into and get back an array. Now let's put some data into it.
function getSynchronizedArray(firebaseRef) { var list = []; syncChanges(list, firebaseRef); return list; } function syncChanges(list, ref) { ref.on('child_added', function _add(snap, prevChild) { var data = snap.val(); data.$id = snap.key(); // assumes data is always an object var pos = positionAfter(list, prevChild); list.splice(pos, 0, data); }); } // similar to indexOf, but uses id to find element function positionFor(list, key) { for(var i = 0, len = list.length; i < len; i++) { if( list[i].$id === key ) { return i; } } return -1; } // using the Firebase API's prevChild behavior, we // place each element in the list after it's prev // sibling or, if prevChild is null, at the beginning function positionAfter(list, prevChild) { if( prevChild === null ) { return 0; } else { var i = positionFor(list, prevChild); if( i === -1 ) { return list.length; } else { return i+1; } } }
Okay, now our array is getting populated from Firebase. Next, let's deal with the other CRUD operations, and move events.
function syncChanges(list, ref) { ref.on('child_added', ...); // example above ref.on('child_removed', function _remove(snap) { var i = positionFor(list, snap.key()); if( i > -1 ) { list.splice(i, 1); } }); ref.on('child_changed', function _change(snap) { var i = positionFor(list, snap.key()); if( i > -1 ) { list[i] = snap.val(); list[i].$id = snap.key(); // assumes data is always an object } }); ref.on('child_moved', function _move(snap, prevChild) { var curPos = positionFor(list, snap.key()); if( curPos > -1 ) { var data = list.splice(curPos, 1)[0]; var newPos = positionAfter(list, prevChild); list.splice(newPos, 0, data); } }); }
Great, now our array is completely synchronized with the remote data. Now we just need some local editing capabilities.
We won't modify our array directly. We can do ops like sort to re-order the data, but if we start trying todo ops like splice or pop, and have the server modifying this array as well, things will get ugly.
sort
splice
pop
Instead, we'll directly push changes to the server with some quick wrapper methods. Since Firebase triggers eventsfor local changes immediately, without waiting for a server response, this is quite performant and simplifies theprocess as well:
function getSynchronizedArray(firebaseRef) { var list = []; syncChanges(list, firebaseRef); wrapLocalCrudOps(list, firebaseRef); return list; } function syncChanges() { /* in examples above */ } function wrapLocalCrudOps(list, firebaseRef) { // we can hack directly on the array to provide some convenience methods list.$add = function(data) { return firebaseRef.push(data); }; list.$remove = function(key) { firebaseRef.child(key).remove(); }; list.$set = function(key, newData) { // make sure we don't accidentally push our $id prop if( newData.hasOwnProperty('$id') ) { delete newData.$id; } firebaseRef.child(key).set(newData); }; list.$indexOf = function(key) { return positionFor(list, key); // positionFor in examples above } }
And there we are! We can now manipulate our array by using operations like this:
var ref = new Firebase(URL); var list = getSynchronizedArray(ref); // add a record var newRecordId = list.$add({ foo: 'bar' }).key(); // remove a record list.$remove(recordKey); // update a record var data = list[5]; data.foo = 'baz'; list.$set( data.$id, data );
That's pretty much it! There are a few additional edge cases that we can cover, but we've created asynchronized array that merges local changes with server updates and keeps all of it in a tidy array.
Here's an example project utilizing these principles you can useas a template for baking your own solutions. Check out the README for installation instructions.
At Firebase, we're never satisfied with just being awesome. We are constantly working to improve all these scenarios and have several API enhancements in the pipeline. Keep an eye on the Google Group for details and announcements.
Find this article useful or have additional questions? Leave a comment below or post a message on the Google Group!