< Articles


Learn Cloud Functions In Six Minutes

When I first heard about cloud functions, I was pretty intimidated. I purposefully avoided them, thinking that anything with the word ‘cloud’ in it had to be pretty advanced. To my surprise, they turned out to be really intuitive and I’ve started making them a mainstay in my app.

What is a cloud function?

A cloud function is a Javascript (or Typescript) function that can be triggered by an HTTP request, an event from other Google Cloud or Firebase features, or a direct call from your client-side code. From your function, you have direct access to Google Cloud and Firebase and can even make requests to other APIs.

Imagine a customer service app where messages between the company representative and the customer are written to your Firestore database. We could use cloud functions, in combination with Google’s sentiment analysis API, to detect frustration in each message. If the customers message reached a certain frustration threshold, we could automatically add in one of our top company representatives to take over and ensure the customer has a good experience.

Or what about a lawn care app that automatically applies discounts if you agree to have your lawn mowed on the same day as other customers in the area? We could use a cloud function to check how many of our customers were in the area, cross reference that info with the day of the week those customers’ lawns are mowed, and then apply some discount based on the result.

How I use cloud functions

When I first created this site, I kept it pretty basic. On the home page, I would make a request to get every post, including the post content. After loading the entire post, I would do some frontend logic to create my 90-character post introduction and my nicely formatted date string. While the actual computation wasn’t too bad, the writing was on the wall for my payload size. With each post, I was adding 1600-2000 characters in text alone. And that’s not factoring in all of the HTML content wrapping my text. Ouch!

It quickly became apparent that I would need to create another root level item in my database. This became my ‘simpleNotes’ collection. In it, I store the nicely formatted date string, a short post excerpt, the title, and the created date time. With minimal effort, I cut my payload size by more than 95%. In fact, the payload for my first post went from 14,500 characters to 150 characters, at least from the context of the home page.

Quick Tutorial

This tutorial assumes you’re already familiar with firebase and have a firebase project that’s set up. If not, go and do that first and then come back.

The first step is to initialize cloud functions in your firebase project. After navigating into the root folder of your firebase project, run the following command:

firebase init functions

As a side note, I recommend selecting Typescript as the language in which you’ll write your functions. After the cli finishes, you’ll notice a functions folder appear at the root level of your project. Inside of that folder, you’ll see a folder called src which contains an index.ts file. This is where we’ll write our cloud functions.

// index.ts

import * as functions from "firebase-functions";
import * as admin from "firebase-admin";

admin.initializeApp({
    credential: admin.credential.applicationDefault(),
    databaseURL: "your-domain.firebaseio.com",
});

export const createShortPost = functions.firestore
    .document("posts/{postId}")
    .onCreate((snapshot, context) => {
        const data = snapshot.data();
        const id = snapshot.id;
        return createSimplePost(data, id);
    });

While this doesn’t show all the code (we’ll show the rest shortly), let analyze what’s going on here. First, importing the functions module from firebase-functions let’s us tap into lifecycle hooks for our firebase documents. Any time a new post is created, the callback that we pass to onCreate is invoked. As well, you’ll notice that we import firebase-admin. This gives us the necessary credentials so that we can write back to our firebase collection with the shortened version of our blog post. Make sense? Cool. Let’s take a look now at what the createSimplePost method does.

// index.ts

// don't worry about this helper method
// it simply creates a nice string for the home page

const constructDateText = (createdTime: number): string => {
    const dateObject = new Date(createdTime);
    const day = dateObject.getDate();
    const month = dateObject.getMonth() + 1;
    const year = dateObject.getFullYear();
    return `${month}.${day}.${year}`;
};

// this is the helper method that we used in the callback passed to onCreate

const createSimplePost = (
    data: FirebaseFirestore.DocumentData | undefined,
    id: string
): Promise<FirebaseFirestore.WriteResult> => {
    const htmlRegex = /(<([^>]+)>)/gi;
    const shortPostContent =
        (data.content as string).replace(htmlRegex, "").slice(0, 90).trim() +
        "...";
    const shortDateText = constructDateText(data.created);

    return admin.firestore().collection("simplePosts").doc(id).set({
        created: data.created,
        title: data.title,
        shortPostContent,
        shortDateText,
    });
};

In our createSimplePost method, we’re using a regex on the incoming post to replace all of the html content with an empty string. Next we’re grabbing the first 90 characters, stripping off any surrounding white space, and appending the short post content with an ellipsis. Still, the most important part of this function is the very end. Here, we use the imported admin module to create a new document in the simplePosts collection. That document will be nested under the same id as it’s associated full length post, albeit in different collections.

One thing that you should be aware of here is that we return a Promise. This is super important. Returning a Promise here, and returning the createSimplePost call in our initial onCreate callback method, ensures that this function won’t finish until the write back to Firestore has completed (or failed).

And that’s it. Cloud functions can make your life significantly easier and make your apps work like magic.