0
votes

I am writing a firebase function using TypeScript to send push notifications to multiple users. But when I run firebase deploy --only functions command, TSLint gives an error "Promises must be handled appropriately".

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

admin.initializeApp(functions.config().firebase);

export const broadcastJob = functions.https.onRequest((request, response) => {
    const db = admin.firestore();
    db.collection('profiles').get().then(snapshot => {
        snapshot.forEach(doc => {
            const deviceToken = doc.data()['deviceToken'];
            admin.messaging().sendToDevice(deviceToken, { //<-- Error on this line
                notification: {
                    title: 'Notification',
                    body: 'You have a new notification'
                }
            });
        });
        response.send(`Broadcasted to ${snapshot.docs.length} users.`);
    }).catch(reason => {
        response.send(reason);
    })
});
1
You're ignoring the promise returned from sendToDevice.Doug Stevenson
I also tried adding catch and then blocks after sendToDevice function, its still giving error.Ali Shahzad
Maybe you could edit the question to show that code instead? What you're showing right now is definitely not right.Doug Stevenson
Please also include your TSLint and TypeScript versions and which line TSLint is complaining on (so we can tell which line in the code you're posting).Josh

1 Answers

0
votes

First a remark, I think you are better of using a callable function instead of onRequest. See: Are Callable Cloud Functions better than HTTP functions?

Next, you need to wait for your asynchronous functions to finish before sending back the response.

In this case you are looping through all your documents returned from the query. For each document you call sendToDevice. This means you are executing multiple async functions in parallel.

You can use:

Promise.all([asyncFunction1, asyncFunction2, ...]).then(() => {
 response.send(`Broadcasted to ${snapshot.docs.length} users.`);
});

The following code is not tested:

export const broadcastJob = functions.https.onRequest((request, response) => {
    const db = admin.firestore();
    db.collection('profiles').get().then(snapshot => {
        Promise.all(snapshot.docs.map(doc => {
            const deviceToken = doc.data()['deviceToken'];
            return admin.messaging().sendToDevice(deviceToken, {
                notification: {
                    title: 'Notification',
                    body: 'You have a new notification'
                }
            });
        })).then(() => {
         response.send(`Broadcasted to ${snapshot.docs.length} users.`);
        }
    }).catch(reason => {
        response.send(reason);
    })
});

Note that I don't use the snapshot.forEach function.

Instead I prefer to use the snapshot.docs property which contains an array of all documents returned by the query and provides all normal array functions such as 'forEach' but also 'map' which I've used here to convert an array of documents into an array of promises.