Getting started with Google Cloud Functions on Firebase
Tags: node, serverless, firebase, beginners
Published: 2019-02-26 00:11:05

---
title: Getting started with Google Cloud Functions on Firebase
published: true
description: You know what they say. In a world full of serverless, deploy... serverless. So, of course, I will do my part. Working on a small project that requires only static pages, the biggest struggle was to find a way to gather feedback from the users through a static form.
tags: nodejs, serverless, firebase, beginner
cover_image: https://thepracticaldev.s3.amazonaws.com/i/xu9m9wwkxra0wtxlr48k.gif
---

You know what they say. _In a world full of serverless, deploy... serverless._ So, of course, I will do my part. Working on a small project that requires _only_ static pages, the biggest struggle was to find a way to gather feedback from the users (through a static form). My first thought was to build a small API that gets the data from the form and stores it in a database. But the traffic on the website is not that heavy, so I didn't see a point to serve an API for 24/7 just for a few requests per week.

The most popular solution that I encountered was, of course, serverless. There are plenty of approaches with [AWS Lambda](https://medium.com/calyx/serverless-contact-forms-with-aws-lambda-79959cd1a6cd) or [Netlify](https://medium.com/@marcmintel/how-to-submit-forms-on-a-static-website-with-vuejs-and-netlify-functions-b901f40f0627). But my static pages were already deployed on [Firebase Hosting](https://firebase.google.com/docs/hosting/), so **I had to** give a try to the [Google Cloud Functions](https://firebase.google.com/docs/functions/) for Firebase.

# Advantages

@adnanrahic does a great job explaining serverless pros and cons (**bonus** a comparison with containers).

{% link https://dev.to/adnanrahic/containers-vs-serverless-from-a-devops-standpoint-e4n#what-is-serverless %}

For this specific project, a serverless architecture is a perfect match: easy to write, deploy and maintain. There is no infrastructure to care about, I can write them in my favorite language using my favorite packages and I can even test them locally. Convenient.

# Getting started

There is no need to set up or scale a server, we will just write the functions and deploy them to Firebase. They will be triggered only when the requests are called.

At this very moment, Google Cloud Functions can be written in [Node.js](https://nodejs.org/) (v6 or v8), [Python](https://python.org/) (beta) or [Go](https://golang.org/) (beta). I will proceed further with Node.js and some additional resources such as [Express](https://www.npmjs.com/package/express) and [CORS](https://www.npmjs.com/package/cors).

## 1. Install Node.js

Make sure that you have [Node.js](https://nodejs.org/) and [npm](https://www.npmjs.com/get-npm) properly configured before you start because we will write the functions in Node.js.

Some people will recommend you [nvm](https://github.com/creationix/nvm) to install and managed Node.js versions.

{% github creationix/nvm %}

But if you can use the [graphical instructions](https://nodejs.org/en/download/) as well.

## 2. Configure Firebase

Sign up or sign in to the [Firebase console](https://console.firebase.google.com/) and create a new project. Doesn't really matter, but I called mine `dev-form-entries`.

Now, setup your project locally.

First, install globally [Firebase CLI](https://github.com/firebase/firebase-tools).

```
npm install -g firebase-tools
```

Now create a local folder for your project.

```bash
mkdir dev-form-entries
cd dev-form-entries
```

While in the project folder, login to Firebase.

```bash
$ firebase login
Success! Logged in as me@tld.com
```

Let's initialize our first Firebase project (you can actually run `firebase init` and add the functions later).

```bash
firebase init functions
```

![Your first Firebase project!!!](https://thepracticaldev.s3.amazonaws.com/i/zvioyw1vwr07712950sn.png)

- **Select a default Firebase project for this directory:** `dev-form-entries`

- **What language would you like to use?** `JavaScript`
    We will use Javascript now. Typescript will work too.

- **Do you want to use ESLint to catch probable bugs?** `No`
    Neat option, but not needed right now.

- **Do you want to install dependencies with npm now?** `Yes`
    Run that `npm install` to install `firebase-functions` and `firebase-admin` for you.

Ok, so let's see what we've got

- `firebase.json` for configuring [Firebase Hosting](https://firebase.google.com/docs/hosting/full-config),
- `.firebaserc` for configuring multiple projects,
- `functions/index.js` is the boilerplate provided by Firebase. We will get back to that soon.

## 3. Configure Realtime Database

Not too much to configure here, because it will be initialized programmatically. But I want to mention them before it's too late.

As I mentioned before, I wanted to store all the data in a database. Firebase has two great out-of-the-box databases that you can use, [Realtime Database](https://firebase.google.com/docs/database/) and [Cloud Firestore](https://firebase.google.com/docs/firestore/). Both of them are highly scalable and flexible (I will get to this later) but I choose to use Realtime Database because it doesn't need any sort of pre-configuration, we will just reference it from the code.

@aurelkurtula might give you a glimpse of the Realtime Database's greatness.

{% link https://dev.to/aurelkurtula/introduction-to-firebases-real-time-database-89l %}

# Deploying to Firebase

## Hello from Firebase

Let's start with Firebase's hello world. Edit `functions/index.js` and keep their example.

```javascript
const functions = require('firebase-functions');

// Create and Deploy Your First Cloud Functions
// https://firebase.google.com/docs/functions/write-firebase-functions

exports.helloWorld = functions.https.onRequest((request, response) => {
    response.send("Hello from Firebase!");
});
```

This function will create a route `/helloWorld` and it will respond with `Hello from Firebase!` on each request.

## Deploy it

Now, your first deployment.

```bash
firebase deploy --only functions
```

Or you can run just `firebase deploy` since the project contains only one function at this moment.

```text
=== Deploying to 'dev-form-entries'...

i  deploying functions
i  functions: ensuring necessary APIs are enabled...
✔  functions: all necessary APIs are enabled
i  functions: preparing functions directory for uploading...
i  functions: packaged functions (42.53 KB) for uploading
✔  functions: functions folder uploaded successfully
i  functions: updating Node.js 6 function helloWorld(us-central1)...
✔  functions[helloWorld(us-central1)]: Successful update operation. 

✔  Deploy complete!
```

Now that your deployment is complete, you can go to your [Firebase console](https://console.firebase.google.com/) and find your function.

![My Google Cloud Functions in the Firebase Console](https://thepracticaldev.s3.amazonaws.com/i/a7vr8pnkoj89eqhb6q8u.png)

That's a neat Dashboard. You can check the health and read the logs of your functions. You can get redirected to Google Cloud Platform to see the full details and quotas.

## Test it

I will use [Postman](https://www.getpostman.com/) to test the functions. Postman is a nice tool to test your APIs, I will cover only the super basics today, but you check @harshitrathod's beginner guide or take a deep look into it, by [Going beyond with Postman](https://dev.to/ebanx/going-beyond-with-postman-522f) with @jlozovei.

{% link https://dev.to/harshitrathod/introduction-to-postman-rest-client-748 %}

As seen in the dashboard, my function's route is `https://us-central1-dev-form-entries.cloudfunctions.net/helloWorld`. I will paste it in Postman and make a `GET` request.

![Successful response got in Postman](https://thepracticaldev.s3.amazonaws.com/i/m69zer7hr0rjwhydt112.png)

# Writing the API

Ok, so now you know where to write, deploy and test the code. Let's try to do something real.

## Warming up

### Express and CORS

As little helpers for our great goal, we will use [Express](https://www.npmjs.com/package/express) (for the middleware and nicer routes writing) and [CORS](https://www.npmjs.com/package/cors) (for enabling all CORS requests, if you're not familiar with it, take a look at some of the @effingkay's CORS concepts).

{% link https://dev.to/effingkay/cors-preflighted-requests--options-method-3024 %}

First, you will need to install them, so pop into your terminal

```bash
npm install --save express cors
```

and add them at the top of your `index.js` file.

```javascript
const express = require('express');
const cors = require('cors');
```

Right after, create an instance of Express and write the middleware that will accept all the CORS requests.

```javascript
const app = express();
app.use(cors());
```

You will use the `app` instance to write the routes and you will export it as a Google Cloud Function, as you did with the `helloWorld` one. So write the new one right after the `helloWorld` exports.

```javascript
exports.entries = functions.https.onRequest(app);
```

This will create an `/entries` function. All the routes that we will write for the `app` instance will be available in the `entries` function.

### Realtime Database

In order to use the Realtime Databases, you will need to import and initialize it.

```javascript
const admin = require('firebase-admin');
admin.initializeApp();
```

## POST entries

I would normally start with the `GET` route, but we need the entries before we can get them. So you will write the `POST` route to push data to the database.

A basic example of an Express `POST /` route is

```javascript
app.post('/', (request, response) {
  // send stuff...
});
```

The fun thing about Realtime Database is that it is fully flexible, so you don't need to design a whole structure beforehand. Since it stores the data as one JSON tree, we can push a JSON structure and it will be enough. Of course, there needs to be validation involved if all the fields are pushed to the database, but this a nice talk for another time.

So the entry that will be stored in the database will be the body of the request itself.

```javascript
const entry = request.body;
```

The way data is pushed to the database is

```javascript
return admin.database().ref('/entries').push(entry);
```

`/entries` being the path to the database reference.

The `push` function returns a promise that we will use to validate and send the response. On fulfilled, we will return the entry pushed and `200` status code. Otherwise, catch and send the error as an `Internal Server Error`. 

```javascript
return admin.database().ref('/entries').push(entry)
    .then(() => {
        return response.status(200).send(entry)
    }).catch(error => {
        console.error(error);
        return response.status(500).send('Oh no! Error: ' + error);
    });
```

At the very core of it, that's it!

{% gist https://gist.github.com/BogDAAAMN/2f408e316bf1449913e1d7ad6360fbbf %}

After a quick deploy, I take it in Postman and make a POST request to `/entries`.

```text
name:John Doe
subject:dev.to
message:Hello dev.to!
```

![Postman's expected response](https://thepracticaldev.s3.amazonaws.com/i/khc6w1wka8wpctm84qm5.png)

If you browse to your [Firebase console](https://console.firebase.google.com/), under **Database** you will be able to see all the entries.

![Realtime Database entries in my Firebase Console](https://thepracticaldev.s3.amazonaws.com/i/l1upr05se5mpet1rarcx.png)

## GET entries

To get all the data for the database, we will use

```javascript
admin.database(...).ref(...).on(...)
```

that will return through a callback all the entries that exist.

This is actually a listener function, so each time there is a new entry in the database, it will be called (cool if you have a static page to monitor those entries).

No promises this time, just a callback that returns the value in a `snapshot`.

```javascript
app.get("/", (request, response) => {
    return admin.database().ref('/entries').on("value", snapshot => {
        return response.status(200).send(snapshot.val());
    }, error => {
        console.error(error);
        return response.status(500).send('Oh no! Error: ' + error);
    });
});
```

Calling it in Postman I got a JSON with all the entries.

```JSON
{
    "-LZadZujD5Qb1MrQvAd_": {
        "message": "Hello, dev.to!!!",
        "name": "John Doe",
        "subject": "dev.to"
    },
    "-LZaeMZYJjQ2weey6k7H": {
        "message": "Hello dev.to!",
        "name": "Jess Doe",
        "subject": "dev.to"
    },
    "-LZaeQc8DAOn0A6B1Gzc": {
        "message": "Hello dev.to!",
        "name": "Jane Doe",
        "subject": "dev.to"
    }
}
```

## Sticking everything together

{% gist https://gist.github.com/BogDAAAMN/0121b5815a8b414ba318f89137b9233d %}

If you deploy them, you can monitor the functions from the dashboard.

![All the Google Cloud Functions in the Firebase Console](https://thepracticaldev.s3.amazonaws.com/i/j4emrsz27awz8air2x3t.png)

But note that you will not be able to see the quotas for each route if you write them for the same instance of an Express app.

## Testing the functions locally

It would be a pain in the ass to deploy to Firebase all the small changes just to test them. Firebase allows you to test all these functions locally.

```bash
firebase serve --only functions
```

This will serve your functions locally, just use the links generated in your terminal.

```text
✔  functions: entries: http://localhost:5000/dev-form-entries/us-central1/entries
✔  functions: helloWorld: http://localhost:5000/dev-form-entries/us-central1/helloWorld
```

# Finale

That's really not much at all. This is just a glimpse of the greatness of Serverless APIs, Google Cloud Functions and Realtime Databases on Firebase. There are other ways to deal with data (such as deleting or updating it). There is a lot of validation and security layers that **you should** add on top of these.

That's the basics that I want to share, I am actually considering writing a whole series about Serverless APIs on Firebase, while I document myself on the topic. Please let me know how are you using Firebase and what fancy stuff are you doing with all the features.

Love!