Getting started with Cloud Functions for Firebase

Android Craftsman @Novoda

Cloud Functions for Firebase, the latest tool added to the Firebase toolbox lets you do all the wild things with Firebase that you always wanted to do. In this blog post we will take a look at how you can get started with the Cloud Functions even if you have no experience with JavaScript.

Novoda have wished for cloud functions ever since we first started playing around with Firebase (see Bonfire). At the time we were just wishing for the ability to execute a piece of code when there are changes in the Real Time Database. However, with this latest Firebase addition you can execute code not only on database changes but also on analytics events, authentication events and much more.

Setting up Cloud Functions with JavaScript

Currently, Cloud Functions only support Node.js, as opposed to AWS Lambdas, which also support Python 2.7 and Java 8. If you’re a native mobile developer like us, this might sound scary to you, but don’t worry, it’s fun!

First thing you’ll need to install is NodeJS. The easiest way on MacOS is to use Homebrew and run:

brew install npm

Next step is to install Firebase CLI tools and initialize the Cloud Functions in your project. All the steps are described in the official documentation but here are the commands you’ll need to run:

npm install -g firebase-tools

firebase login

And then finally go inside your project directory and run this command to initialize the functions.

firebase init functions

Now you’re all set for the Cloud Functions. Let’s have a look at what you need to configure in order to allow you to run tests.

Testing Firebase cloud functions

In our project we’re using the testing framework called Jasmine and a code coverage tool called Istanbul. Since this is the JavaScript world you could choose any of the plethora of the libraries and tools available.

To install these libraries to your project, just go inside the functions folder and run the following command:

npm install istanbul jasmine --save-dev

This will download the dependencies into your project and also add these libraries as devDependencies into your project.json file.

To initialise Jasmine, all you need to do is run this command:

jasmine init

This will generate all the necessary Jasmine configuration files and allow you to run the tests. However, we were not really happy with the default configuration so we decided to move things around a bit, mainly because we wanted to have both source files and test files together.

As the first step we moved our jasmine.json file to the functions folder and changed the spec_dir to src which is the directory that contains all our code. The final configuration file looks like this:

{
  "spec_dir": "src",
  "spec_files": [
    "**/*[sS]pec.js"
  ],
  "helpers": [
    "mocks/**/*.js"
  ],
  "stopSpecOnExpectationFailure": false,
  "random": false
}

Next we had to tell Jasmine where to find the configuration file. We do this in the package.json file. Adding the test script into the package.json also allows us to run the tests by simply executing npm test command which will be also handy for running the tests on the CI.

"scripts": {
    "test": node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=jasmine.json
  }

The last step is to configure the code coverage tool, you can do this by updating the test script we defined earlier so that it contains the following command:

"scripts": {
    "test": "./node_modules/.bin/istanbul cover -x \"**/*[sS]pec.js\" node_modules/jasmine/bin/jasmine.js JASMINE_CONFIG_PATH=jasmine.json && ./node_modules/.bin/istanbul report cobertura"
  }

Here we’re telling Istanbul to run the code coverage of the Jasmine tests excluding spec files. The last part of the command is optional, since it only generates the cobertura test report so that it can be visualized on the CI and make your build fail in case the code coverage falls below a certain threshold. But that also requires a little bit of configuration on your CI server.

Creating your first cloud function

You may have noticed that we have been talking about a src folder but there is index.js already generated for us in the root of our project. This is the file where we need to export our functions so that they can be deployed. However, this file is not included in our tests or code coverage setup, so we don’t want to have any logic here; we only want to use it to let Firebase know about our functions.

We ended up creating another index.js file inside the src folder and moving all the contents of the root-level index.js there. Then the only thing we added into the root-level index is a single line of code that lets Firebase know about the functions we want to export:

module.exports = require('./src/index');  

In this simple case the exports are the same in both index files so this seems like a bit of an overkill. But with this setup we can structure our source code in a completely different way without affecting how we export functions to Firebase. We could even write all our logic in TypeScript and all we would need to change here is the location of the index.js we require from the current JavaScript file to the location of the compiled index.ts.

Now we can write a simple test database function in the src/index.js. Our hello world function writes the value of anything that just got written in the database to the console log. Here’s the code of the function:

var functions = require('firebase-functions');

exports.helloWorld = functions.database.ref('/')  
    .onWrite(event => {
        console.log('New data: ', event.data.val());
    });

Push it to the Firebase cloud ☁️

Our awesome function is ready to be deployed now. We can do that by simply calling a single command in the root of our functions folder.

firebase deploy --only functions

When the deploy finishes you can see your functions in the Functions section of the Firebase Console, where you will also find the logs and usage statistics. The console contains only the very basic information, which is perfectly sufficient most of the time. However, if you need to find some more information, then you can always head over to the Google Cloud Platform Console and look for it there.

Conclusions

Thanks to the fact that Novoda is a part of the Google Agency Program we’ve had a chance to work with the Cloud Functions for Firebase for a while now. We are definitely excited about the possibilities that they offer together with other Firebase tools and we will be sharing more about our experiences with it in future blog posts. In addition to that, we will be talking about the Functions in this month’s episode of our monthly Firebase Hangout.

Thanks to Andrei for his help with the blog post and to Francesco and Daniele for their help with JavaScript. Don’t forget to checkout our Bonfire app that uses Firebase.

Bonfire logo
Get it on Google Play
Android, Google Play and the Google Play logo are trademarks of Google Inc.
The iOS app hasn’t made it through the app review process, but you can sign up to our beta

About Novoda

We plan, design, and develop the world’s most desirable software products. Our team’s expertise helps brands like Sony, Motorola, Tesco, Channel4, BBC, and News Corp build fully customized Android devices or simply make their mobile experiences the best on the market. Since 2008, our full in-house teams work from London, Liverpool, Berlin, Barcelona, and NYC.

Let’s get in contact