Cloud Functions for firebase are an awesome solutions for running backend code in response of Firebase events and HTTP requests.
You don’t need to manage your server: just deploy the JavaScript code and let Google do the rest. That way, you won’t need to pay for a server which is running 24/7 even when you get no HTTP requests; you’ll only pay a fixed amount of money for each Function execution, which is way cheaper!

What could you do with Firebase Cloud Functions?

As we said before, you can run your backend code in response of Firebase events or HTTP requests.
For instance, pretend that an user is uploading a picture to Firebase Storage. You could easily generate thumbnails from that image and store their path inside Firebase Firestore, a NoSQL realtime database!

You could also write a Serverless REST API with Express.js and deploy it in a metter of seconds... and that’s what we’ll see today!

Bootstrapping the Function

First of all, let’s fo to the Firebase Admin Console and let’s add a new project.

Then let’s install Firebase Tools on your machine:

$ npm install -g firebase-tools

Great! Now let’s login in your Firebase account from your command line:

$ firebase login

Now you’re ready to bootstrap your function! That’s how you’ll do it:

via Gfycat

Now you should have the following folder structure:

myproject
  |
  +- .firebaserc
  |
  +- firebase.json
  |
  +- functions
      |
      +- .eslintrc.json
      |
      +- package.json
      |
      +- index.js
      |
      +- node_modules/

We’re ready to write our REST API!
Let’s move inside the functions directory and install the required dependencies:

$ npm install --save express body-parser cors

Now let’s open the functions/index.js file and let’s write up our Firebase Cloud Function!

const functions = require("firebase-functions");
const server    = require("./src/server");
const api       = functions
                  .runWith({ memory: "2GB", timeoutSeconds: 120 })
                  .https
                  .onRequest(server);

module.exports = {
  api
}

Let’s analyze the code above:

  1. We require the firebase-functions module.
  2. We require a server module. here we’ll write our REST server.
  3. We declare a new api constant, which is the Firebase Cloud Function handler: everytime we’ll get an HTTP request, we’ll allocate 2GB of memory and a maximum of 120 seconds for executing the function.
    We also declare that it will be served under HTTP, and the request will be handled by the server module.
  4. We just export the api function. It will be reachable over the https://<your-project>/api endpoint.

Now let’s move inside our server module:

const express    = require("express");
const bodyParser = require("body-parser");
const cors       = require("cors");
const app        = express();

app.use(cors({ origin: true }))
   .use(bodyParser.json())
   .use(bodyParser.urlencoded({ extended: false }))
   .use("/languages", require("./lib/languages/route"))
   .get("*", (_, res) => res.status(404).json({ success: false, data: "Endpoint not found" }));

module.exports = app;

As you can see, we’re creating a standard Express.js app, where we’re basically declaring just an endpoint (/languages) and a * wildcard which will respond with a 404 status page.

Let’s see what’s inside our /lib/languages/route.js file:

const router     = require("express").Router();
const controller = require("./controller");

router.get("/all",       controller.getAllLanguages);
router.get("/:language", controller.getLanguage);

module.exports = router;

Just routes! We’ll delegate to our /lib/languages/controller.js file the handler for these two routes:

const languages = require("./languages.json");

function getAllLanguages(req, res) {
  return res.json({
    success: true,
    data: languages
  });
}

function getLanguage(req, res) {
  const requiredLang = req.params.language;
  const lang         = languages.filter((lang) => lang.name === requiredLang);
  const exists       = lang.length > 0;

  return res
         .status(exists ? 200 : 400)
         .json({
           success: exists,
           data: exists ? lang[0] : "Language not found"
         })
}

module.exports = {
  getAllLanguages,
  getLanguage
}

As you can see, we’re just creating two controllers which are taking their data from a local JSON file, but it could have been a database call or any other data source.

In the getAllLanguages function, we’re just sending back an array of programming languages ridden from the languages.json file.
In the getLanguage function, we’re doing something a bit more complex:

  1. We’re taking the desired programming language as an Express.js parameter (/languages/:language).
  2. We’re getting that language from the JSON file
  3. We’re controlling if the lang variable is valorized with an array of one item.
  4. Now we’re sending back a response to the user: if the desired language exists in our JSON file, we’ll send back a 200 status code. Otherwise we’ll send a 404.
  5. Then we’re sending back the desired language (if exists) or a friendly error message.

Testing the Function

We’re now ready to test our function locally... and Firebase makes it easy! Let’s just go to the /functions directory and tipe:

$ firebase serve

That will bootstrap a local server with an endpoint like this: http://localhost:5000/jsmonday-cms/us-central1/api, where you can test your API! Just try to go to the following URL and see what you get back:

http://localhost:5000/jsmonday-cms/us-central1/api/languages/all

Deploying the Function

If testing the function locally was easy… deploying it is even easier! Just type the following command:

$ firebase deploy

Your function is now ready to be called from the whole internet!

Did you like this article? Consider becoming a Patron!

This article is CC0 1.0 (Public Domain) licensed.