As a developer, the best way to learn any new technology is by diving in and building simple applications. Recently, we explored whether Google Cloud Functions (a.k.a GCF - Google’s answer to AWS Lamda) can be used with Expo to handle server-side functionality for push notifiations within a React Native application.

As it turns out, it’s a breeze. In this post, we’ll be taking a look at how to set up server-side push notifications using Expo and Google Cloud Functions.

Project Setup

The setup is simple. Expo provides a NodeJS server-side library for push notifications.

First, create a new project and add the Exponent Server SDK for Node.

yarn init
yarn add exponent-server-sdk

The library accepts several juicy nuggets of data, the most important one being the authorized push token issued created by the mobile device, and sends that data to the Expo push notification servers.

JavaScript

Next create an index.js file and copy/paste in the example code found in the README file in the lib’s GitHub repo. This file will be what we export as a Google Cloud Function. Here’s the off-the-shelf sample code:

import Expo from 'exponent-server-sdk';

// To check if something is a push token
let isPushToken = Expo.isExponentPushToken(somePushToken);

// Create a new Expo SDK client
let expo = new Expo();

// To send push notifications -- note that there is a limit on the number of
// notifications you can send at once, use expo.chunkPushNotifications()
(async function() {
  try {
    let receipts = await expo.sendPushNotificationsAsync([{
      // The push token for the app user to whom you want to send the notification
      to: 'ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]',
      sound: 'default',
      body: 'This is a test notification',
      data: {withSome: 'data'},
    }]);
    console.log(receipts);
  } catch (error) {
    console.error(error);
  }
})();

This code is all well and great, but we need to make some changes to make it work in GCF. We’ll need to:

  1. Export the function as a named function.
  2. Add the authorized push token from our mobile app.
  3. Return appropriate responses.

Like so:

import Expo from 'exponent-server-sdk';

// Create a new Expo SDK client
let expo = new Expo();

// To send push notifications -- note that there is a limit on the number of
// notifications you can send at once, use expo.chunkPushNotifications()
exports.sendNotification = async function(req, res) {
  try {
    let receipts = await expo.sendPushNotificationsAsync([{
      // The push token for the app user to whom you want to send the notification
      to: req.body.token,
      sound: 'default',
      body: 'This is a test notification',
      data: {withSome: 'data'},
    }]);
    return res.status(200).json(receipts)
  } catch (error) {
    return res.status(500).json({error: error})
  }
};

Transpile with Babel

If you try to paste this in to Google Cloud Function, it will fail as LTS NodeJS still doesn’t support all ES6 features in their entirety.

So we’ll have transpile our ES6 code using Babel. We could have used WebPack, but that would mean introducing some additional complexity via config files that are IMO unnecessary for this exercise.

yarn add -D babel-cli babel-plugin-syntax-async-functions babel-plugin-transform-regenerator babel-polyfill babel-preset-es2015

Then we’ll require babel-polyfill at the top of our code.

require('babel-polyfill');

import Expo from 'exponent-server-sdk';

// Create a new Expo SDK client
let expo = new Expo();

// To send push notifications -- note that there is a limit on the number of
// notifications you can send at once, use expo.chunkPushNotifications()
exports.sendNotification = async function(req, res) {
  try {
    let receipts = await expo.sendPushNotificationsAsync([{
      // The push token for the app user to whom you want to send the notification
      to: req.body.token,
      sound: 'default',
      body: req.body.message,
      data: {withSome: 'data'},
    }]);
    return res.status(200).json(receipts)
  } catch (error) {
    return res.status(500).json({error: error})
  }
};

Next we’ll need a way to execute the Babel transpiler. We’ll do that by adding a “scripts” entry in our package.json. I’ve chosen to write a script that simply copies the transpiled file into a “functions” directory within the root directory. Your package.json should look something like this:

{
  "name": "expo-gcf",
  "scripts": {
    "build": "babel 'index.js' --out-dir 'functions' --copy-files --ignore 'node_modules'"
  },
  "dependencies": {
    "exponent-server-sdk": "^2.3.1"
  },
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-plugin-syntax-async-functions": "^6.13.0",
    "babel-plugin-transform-regenerator": "^6.24.1",
    "babel-polyfill": "^6.23.0",
    "babel-preset-es2015": "^6.24.1"
  }
}

Next, create a .babelrc file in the root.

{
  "presets": ["es2015"],
  "plugins": ["syntax-async-functions","transform-regenerator"]
}

Then at the command line, simply run:

yarn build

You should now see the transpiled code in index.js within a newly-created functions directory.

Create your Google Cloud Function

Now we’re ready for placement of our code in Google Cloud Functions.

From Google Cloud Console menu, click Cloud Functions.

Google Cloud Console menu with Google Cloud Functions

Create a new Function by clicking…<drum roll, please>…”Create Function”.

  • Name the function whatever you like.
  • Change the Memory Allocated to the lowest possible (128MB as of today).
  • Select Inline Editor from the Source Code list.
  • Copy/Paste your transpiled code into the textarea.
  • Select a stage bucket.
  • Under “Function to execute,” make sure to put the name of the function you want to call. In our case, it’s sendNotification.

After the system grabs all of the dependencies and completes setup, your function is created and ready for use.

To use the function in your app, simply POST the token key to the trigger URL assigned to your function.

{
  "token": "myauthorizedpushtokenhere"
}

You’ll find the trigger URL in the Trigger tab of your function.

Google Cloud Functions trigger url

Test your Google Cloud Function

You can also test your function from within the Testing tab. Simply place a JSON object within the Triggering Event textarea and click Test.

Google Cloud Functions testing

For more information on how to set up Notifications in Expo, check out their Notifications documentation.

TL;DR

You can view the project files in GitHub - https://github.com/nolangarrido/expo-google-cloud-functions-push-notifications.