Slack Bot Using AWS Lambda and DynamoDB

I have a Slack account setup with some friends of mine, and we created a #stayfit room to keep each other motivated.

I thought it would be a cool idea to create a bot for the room where we could post our workouts and it would keep track of it. Since it’s going to be a very low volume task, it’s perfect for pay-by-the-request Amazon Web Services.

Here’s the end result:

Type: /workout

This code is up on Github here:

There are 4 parts you need to have in place for the full system to work:

  1. A new Lambda function with your application logic
  2. An API endpoint using AWS API Gateway - this will point to your Lambda function
  3. A new blank DynamoDB database. It’s schemaless, so you don’t need to define your data structure, but you do need to define the container
  4. A custom Slash Command at Slack to POST to your API endpoint

AWS actually gives you a nice template to start from, which helps because the authentication process to get a kmsEncyptedToken created isn’t terribly straight forward. I won’t copy the instructions here, since they may continue to get updated. Instead, just follow these steps:

  1. Login to the AWS Management Console
  2. Click Lambda under the Compute section
  3. Click Create a Lambda Function
  4. Search for “slack” from the set of templates and select “slack-echo-command”
  5. Follow the instructions in the comments to setup your initial test

In Lambda, you define a single function that will execute first, by default named handler in the Lambda configuration page (but can be named whatever you would like) and needs to be exported with node’s normal export process. Here is the main function you’ll want for this integration, since up front you need to validate the API token sent from Slack before processing the event.

var token;
var kmsEncyptedToken = 'YOUR_TOKEN_GOES_HERE';

// Setup the Lambda POST handler
exports.handler = function(event, context) {
    if (token) {
        // Container reuse
        processEvent(event, context);
    } else if (kmsEncyptedToken) {
        var encryptedBuf = new Buffer(kmsEncyptedToken, 'base64');
        var cipherText = {CiphertextBlob: encryptedBuf};

        var kms = new AWS.KMS();
        kms.decrypt(cipherText, function (err, data) {
            if (err) {
                console.log('Decrypt error: ' + err);
            } else {
                token = data.Plaintext.toString('ascii');
                // Successfully authenticated, run the app
                processEvent(event, context);
    } else {'Token has not been set.');

You can then parse the body off the event that is passed. Here I’m using qs to parse the body.

function processEvent(event, context) {
    var body = event.body;
    var params = qs.parse(body);

    var username = params.user_name;
    var command = params.text;
    var responseUrl = params.response_url;
    var channelName = params.channel_name;
    // ... App logic here...

When you have your completed app, zip all the files and upload them to your Lambda function. Remember that you need to include the entire node_modules folder in your upload. Lambda will not do an npm install for you.