Send Push Messages with Firebase Cloud Functions + Firestore

logo_firebase

Firebase is a great tool for sending push messages. This example is a simple integration of push messages on Cloud Functions. We will use Firestore for the DB over Realtime Database this time.

Feature Definition

  • Register a user device token to Firebase on the initial setting of a time clock app.
  • Send a push reminder if the notification is enabled and the user hasn't clocked in 10 min before.
  • Deploy the process to Cloud Functions with Node.js, and call the generated URL from the internal server with cron.

Structure

Firestore

users
|- id
|- fcmToken
|- isEnabled
|- isClockedIn

The user data on Firestore only contains the token, push setting, and clock-in status.

Environment

Vagrant Ubuntu Xenial Node.js 8

Cloud Functions can be easily deployed with Node.js. I'd like to use Node LTS 10, but I'm using version 8 since the Firebase runtime is 8 at this moment. Beware that Xenial will install the old version of nodejs if you simply use apt-get.

Firebase SDK

After installing Node.js and npm, global-install the Firebase SDK.

$ npm install -g firebase-tools

Login to Firebase

After running the command, it will as if it's ok for it to send anonymous data to Firebase. The login process is completed when you open the URL displayed on the terminal.

$ firebase login

Firebase Functions

We will init in the app directory. Here, you can choose JavaScript or TypeScript for app development. After files/directories are automatically created, we will install the firebase module in the functions directory.

$ mkdir APP_DIR
$ cd APP_DIR
$ firebase init functions
$ cd functions
$ npm i -s firebase-functions@latest firebase-admin@latest

The Node.js runtime is 14 by default, but you can also choose 12 or 10. If you would like to use 12, edit the node version on functions/package.json. The structure is as same as dependencies.

// package.json
{
// ...
"engines": { "node": "12" }
// ...
}

Implement the Logic

First, initialize firebase-admin.

The syntax for functions we want to implement can be written as exports.ENDPOINT. In other words, the function names will become endpoints.

Now let's write some Promise chains. We have to choose the event we would like to trigger first. For example, we would call functions.http.onRequest() if triggering on each request to the URL, functions.database.ref().onEVENT() if we want to trigger with Realtime DB, or functions.firestore.document().onEVENT() for Firestore. Read more about it here.

The Firestore instance can be accessible with admin.firestore(), and we can get the snapshot by selecting collection and call get(). Then, we run forEach here to get each document. The id can be accessed with .id. For other attributes, we need to call data() to get the data bundle, and use each key to access attributes.

Gather all tokens in an array for users who set the notification enabled and haven’t clocked in.

Now we have the tokens, it's time to send push messages with admin.messaging().sendToDevice(). The first arg is an array of token strings, and the second is the payload.

Check the result Promise object if there is an error. I'm not adding any process here but it would be a good idea to remove the token in the case of an invalid token error. This is Node.js http.Response by the way.

The whole script

Deploy!

Deployment can be done with the Firebase SDK command. Make sure the account is authorized to execute this.

$ firebase deploy --only functions --project PROJECT_ID

If a url is displayed, that means the deployment was successful. You can also see the deployment status on the Firebase console. Now, every time you tap this url, push notifications would be fired.

The repo of this project is here.

References

COPYRIGHT © 2023 Kohei Ando