Packaged Slack NodeJS Lambda

Objective

At Galactic Fog we needed a way to funnel our web sales notifications from our website to a private Slack channel. However, we had no desire to build a stand alone web service and deal with its inherit complexities. Normally, we would write a simple nodejs server, host, maintain and integrate the process into our CI pipeline. The server would always be running, requiring additional resources and monitoring. This is a perfect task for a lambda function!

Similar to Inline NodeJS Lambda, we are going to create nodejs lambda that sends a message to a slack channel, but this time, we are going to build our lambda as a package so we can utilize 3rd party libraries such as axios to manage our REST API side effects.

Requirements

  • Implement App As Serverless Solution
  • Expose publicly for our website
  • Obfuscate any potentially sensitive information from the client
  • Provide some sort of thottling
  • Using 3rd party libraries to build our lambda
  • Host our lambda in github

Pre Requisites

  • You are authenticated and authorized to Gestalt Platform
  • You have already defined a Hierarchy (Org, Workspace, Environment)
  • You have already defined an API in Gestalt Platform
  • You have configured a slack web hook
  • You have git, npm and node and installed

Resources

Create the lambda Package

mkdir hello_slack

Create a package.json file

{
  "name": "hello_slack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "author": "John Betancur",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.17.1"
  }
}

Note

Note that the main is index.js - we will reference this value later in Gestalt Ui.

Install the dependancies

npm install

Create the index.js.

Note

Your exports needs to be in ES5 style but the function code can be ES6.

var exports = module.exports = {};
exports.run = function (event, context, callback) {
  // let's do this is es6 style
  const axios = require("axios");
  const host = process.env.SLACK_API_BASEPATH;
  const path = process.env.SLACK_PATH;
  const slackAPI = axios.create({
    baseURL: host,
    headers: { 'Content-Type': 'application/json' }
  });

  const postMessage = async (path) => {
    try {
      const eventData = JSON.parse(event);
      const message = eventData && eventData.data.payload || 'a payload was not provided to the message';
      const body = { text: message }; // this is what the slack api expects
      const response = await slackAPI.post(path, body);
      callback(null, 'SUCCESS');
    } catch (err) {
      callback(err, 'ERROR');
    }
  }

  postMessage(path);
};

Let's test out our slack lambda by installing the laser CLI

npm install -g laser-execute

Note

Usage
laser-execute /full/path/to/your/handler/file.js handlerFunction '{ somedata : "here" }' <context_would_go_here_but_not_available_locally>

Run the following command/args to test out our lambda

laser-execute $(echo `pwd`)/index.js run '{ "data": { "payload": "hello slack!" } }'

Great! Now, if we want to publish our lambda we have two options. We can check in our code as well as node_modules into git, or we can zip up our hello_slack directory and host it on a file share, S3, Github or really anywhere that hosts files and allows public access. For this guide we will go with the Github option.

zip -r hello_slack.zip .
git add .
git commit -m 'hello slack lambda'
git push // assuming you already setup your git repo origin

Create the API for posting messages to a slack channel

Define the Lambda

  1. Navigate to your desired Environment and on the Create Menu Click Create Lambda
  2. Select the desired Lambda Provider and Name
  3. Select the a NodeJS Runtime and select Package Code Type
  4. Specify the Handler as index.js;run
  5. In Package URL paste in https://github.com/<youraccount</<your-repo></your-repo>/tree/master/hello_slack.zip).zip?raw=true
  6. Check Compressed Package

Configure Environment Variables

Environment Variables that are defined on the Lamnda are passed to nodeJS lambdas via process.ENV Here you will need the information that weas generated when you configured your webhook with slack

  1. Define two variables in the Environment Variables
  2. SLACK_API_BASEPATH: https://hooks.slack.com
  3. SLACK_PATH: services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
  4. Click Create

Expose an API Endpoint

Now that we've created our Slack Lambda we need to expose an api endoint.

  1. On the same Lambda screen, in the Public Endpoints section click Add Endpoint
  2. Select an API and click Next
  3. Enter a Relative Path e.g /send
  4. Check only the POST Allowed HTTP Method
  5. Check the Rate Limit and enter 60 (the number of requests allowed per minute)
  6. Click Finish
  7. Click or copy the Public URL which you will use to make your REST API call

Using your favority REST client you can post the following message format using the following settings:

  • URL: The public URL that ws generated when you created the endpoint:
  • Headers: Content-Type: application/json Accept: application/json
  • Method POST
  • Body:
{ "data": { "payload": "Hello Slack!" } }

You should see a message in your slack channel!!!