Search code examples
node.jsfirebasefirebase-realtime-databaseslackgoogle-cloud-functions

How to send firebase data to slack using cloud functions?


I cloned this sample minimal-webhook and got this working. I wanted to extend this functionality by sending the writes to slack.

I am using the incoming webhook of slack. I guess the issue is the way how I add the data payload in nodejs. Can anyone help? Thanks in advance. Attached my code and error log from firebase.

const functions = require('firebase-functions');
const request = require('request-promise');
const WEBHOOK_URL = 'https://hooks.slack.com/services/abc'
var headers = {
    'Content-type': 'application/json'
};
exports.webhook = functions.database.ref('/hooks/{hookId}').onWrite(event => {
  return request({
    uri: WEBHOOK_URL,
    method: 'POST',
    headers: headers,
     body: event.data.toJSON,
    resolveWithFullResponse: true
  }).then(response => {
    if (response.statusCode >= 400) {
      throw new Error(`HTTP Error: ${response.statusCode}`);
    }
    console.log('SUCCESS! Posted', event.data.ref);
  });
});`

Also attached the error log from Firebase


Solution

  • @Bob Snyder is on the right track. However Slack expects certain things when you use web hooks.

    When you send a POST request to the webhook, the following conditions need to be met:

    • Content-Type must be application/json
    • The request body must be properly formatted JSON.
    • The request body must contain one of the following fields: text, fallback or attachments.

    Now, when you store data on firebase, you could store all the information you need in the database, or you can just keep the common stuff in your code and only put the payload (the data you want to send) in the database.

    The following snippet of code will allow you to store whatever you want at the specified location in the database. The data stored there will be transmitted as the text parameter of the web hook in JSON format.

    exports.webhook = functions.database.ref('/hooks/{hookId}').onWrite(event => {
      var body = {
        "channel": "#general",
        "username": "your-bot-name-here",
        "icon_emoji": ":computer:",
        "text": event.data.toJSON()
      };
    
      return request({
        uri: WEBHOOK_URL,
        method: 'POST',
        body: body,
        json: true,
        resolveWithFullResponse: true
      }).then(response => {
        if (response.statusCode >= 400) {
          throw new Error(`HTTP Error: ${response.statusCode}`);
        }
        console.log('SUCCESS! Posted', event.data.ref);
      });
    });
    

    Note: The function toJSON() is added by the DataSnapshot class of Firebase (which event.data is an instance of). If using a different object, the same result can be achieved using JSON.stringify(obj).

    You should also consider checking the type of onWrite() event. There's no point in sending a request to Slack when the data was deleted (use if (!event.data.exists()) { /* data was deleted */ return; }) and you may also want to only send the request once (use if (event.data.previous.exists()) { /* data has been updated */ return; }).

    If you wish to make the message look nicer, you can find information on formatting the text field at https://api.slack.com/docs/messages/builder