An Intro to Using Expo Push Notifications
Tags: reactnative, node, codenewbie
Published: 2020-02-03 00:20:03

I recently implemented push notifications for a native iOS app built on React Native with Expo and a NodeJS/Express server. Expo's Push Notifications API is very handy, but I was initially a bit confused about how to use this tool on my back end. In this blog, I'll run through my solution to this problem, in the hopes that it might help other folks who want to use push notifications in their mobile applications.

## 1. Get and store your user's push token

[Expo's docs](https://docs.expo.io/versions/latest/guides/push-notifications/#1-getting-the-users-push-token) are helpful for this, and they give you a boilerplate function you can use on your front end. 

To do this, I first created a file in our client directory called `registerForPushNotificationsAsync.js`, where I put the following, based off the Expo boilerplate:

```js
import { Notifications } from 'expo';
import * as Permissions from 'expo-permissions';

export default async function registerForPushNotificationsAsync() {
  try {
    const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
    // Stop here if the user did not grant permissions
    if (status !== 'granted') {
      return null;
    }
    // Get the token that identifies this device
    const token = await Notifications.getExpoPushTokenAsync();
    return token; 
  }
  catch(err) {
    console.log(err);
  }
}
```

`Permissions.askAync()` checks to see if the user has granted permission for notifications on their phone from your app. If the status is not granted, we escape the function. Otherwise, we ask the Expo API for a unique token. The token should look something like this: 
```js
ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]
```

In my SignUp component in the React Native front end, I call `registerForPushNotificationsAsync` in the below function, `googleSignUp`, when a user clicks a "sign up" button.

```js
// ...
import registerforPushNotificationsAsync from '../expoPushFunctions/registerForPushNotificationsAsync';
// ...
  const googleSignUp = async () => {
    try {
       // Get user Google auth info and add them to the database .
       // ...
      .then(async () => {
        // call the Expo function we created above
        const expoPushToken = await registerforPushNotificationsAsync();
        return expoPushToken
      })
      // and add the returned token to the user's record in the database
      .then(expoPushToken => {
        axios.patch(`${URL}/users/${user.email}/push`, {
          expoPushToken
        })
      })
      .catch(error => console.log(error));
    } catch(error) {console.log(error)}
  }
// ...
```

So whenever a user signs up (and has allowed notifications from my app), they receive a unique Expo token, which is stored in their personal record in the database.

## 2. Send notifications from back end

I want to send the user notifications whenever a band they follow creates a new show.

### Build the Expo API call 

First, I set up the function that will make the Expo Push Notification API call. I made the file `pushNotifications.js` with the following function, also based on a [boilerplate function](https://github.com/expo/expo-server-sdk-node) from Expo:

```js
const { Expo } = require('expo-server-sdk');
// Create a new Expo client
const expo = new Expo();
const sendNotifications = async (pushTokens, title, body) => {
    try {
        // Create the messages that you want to send to clents
        let messages = [];
        for (let pushToken of pushTokens) {
          // Check that all your push tokens appear to be valid Expo push tokens
          if (!Expo.isExpoPushToken(pushToken)) {
            console.error(`Push token ${pushToken} is not a valid Expo push token`);
            continue;
          }
          // Construct a message
          const message = {
            to: pushToken,
            sound: 'default',
            title,
            body
          }
          messages.push(message)
        }
        // Batching nofications
        let chunks = expo.chunkPushNotifications(messages);
        let tickets = [];
        (async () => {
          for (let chunk of chunks) {
            try {
              let ticketChunk = await expo.sendPushNotificationsAsync(chunk);
              console.log(ticketChunk);
              tickets.push(...ticketChunk);
            } catch (error) {
              console.error(error);
            }
          }
        })();
    }
  }
      catch(err) {
          console.log(err);
      }
}

module.exports = {
    sendNotifications,
    expo
}
```
This function will be passed a title, body, and array of push tokens. I want to be able to use this function for different types of notifications, which is why I'm going to pass in the title and body of the message dynamically. 

The function builds an Expo-compatible message for each user and sends the group of messages out in batches.

### Create the route and the querying function

Like I said, every time a musician creates a new show on my app, I want their followers to be notified. So in a `createShow` function in my database helpers, I added a call to the Expo API through that `sendNotifications` function.

```js
const createShow = async (req, res) => {
    try {
        let { name, dateTime, venueName, bandName } = req.body;
        // store new show in database
        const show = await Show.create({
           // ...
        })

        // For each band playing the show, send push notifications to followers
        await bandNames.forEach(async (bandName) => {
            // Create push tokens array for band followers
            let pushTokens = [];
            const band = await getRecordByName('band', bandName);

            // Get all followers of a given band
            const sql = `SELECT * FROM users WHERE id IN (
                SELECT id_fan FROM fans_bands WHERE id_band = ?)`;
            const followers = await sequelize.query(sql, {
                replacements: [band.id]
            })
            // Push their tokens to the pushTokens array
            followers.forEach(follower => {
                pushTokens.push(follower.expoPushToken)
            })
            // Construct title and body for message
            const title = `New show from ${band.name}!`;
            const body = 'Open Dive for more info.';
            await sendNotifications(pushTokens, title, body);
        })
        res.sendStatus(201);
    }
    catch (err) {
        console.log(err);
        res.sendStatus(400);
    }
}
```

I've created an account in the app and followed a band to test this functionality out. With the app in the background on my phone, when I use Postman to create a sample show, I get the following result:

![Imgur](https://i.imgur.com/Cxx4N1o.png?1)

And that's it! This is just one example of how you can use Expo's push notifications API, and I hope seeing this solution has helped make that process more clear.