Create a Slack slash command with AWS Lambda

Login/create an AWS account and click the Lambda icon.

Click the Create a Lambda function button.

You now need to select a blueprint, type hello into the box and click the Hello-World NodeJS example (or select a language of your choice).

This will create the basic code for your Lambda. Replace the default code with this:

console.log(‘Loading function’);
exports.handler = function(event, context) {
//Echo back the text the user typed in
context.succeed('You sent: ' + event.text);
};

Give your Lambda a Name and Description.

We now need to create a Role. Select * Basic execution role at the bottom of the page. In the popup window, select Create a new IAM Role and give the role a name

Select “Allow” and go back to your Lambda tab and select this new role from the dropdown.

Click Next, then Create Function.

To POST or not to POST

Slack can either POST data to your application or put it in the query string with GET.

The lambda will in either case create a JSON value for you to use.

Getting access to your code

Now that we have the code setup we need a URL. In AWS go to the API Gateway section.

Click the “Create API” button and fill in the details.

Click the Create method button in the top right, and select POST from the drop down on the left (and click the small tick). You could also have selected GET if you set Slack up to use GET requests.

In the Integration type select Lambda function, and select the region your AWS account is set to and start typing for a list of your lambdas to appear.

Click “Save”.

POST-ing data

You can skip this step if you set Slack to GET instead of POST.

This section of the tutorial is taken from: https://forums.aws.amazon.com/thread.jspa?messageID=673012&tstart=0#673012

On the following screen click the box Integration Request and scroll down to the Mapping Requests section.

Click Add mapping template and type application/json into the box and click the small tick. Click the pen icon next to the word Input passthrough and select Mapping template from the dropdown.

In the Template box put this code:

## convert HTML POST data or HTTP GET query string to JSON

## get the raw post data from the AWS built-in variable and give it a nicer name
#if ($context.httpMethod == "POST")
#set($rawAPIData = $input.path('$'))
#elseif ($context.httpMethod == "GET")
#set($rawAPIData = $input.params().querystring)
#set($rawAPIData = $rawAPIData.toString())
#set($rawAPIDataLength = $rawAPIData.length() - 1)
#set($rawAPIData = $rawAPIData.substring(1, $rawAPIDataLength))
#set($rawAPIData = $rawAPIData.replace(", ", "&"))
#else
#set($rawAPIData = "")
#end

## first we get the number of "&" in the string, this tells us if there is more than one key value pair
#set($countAmpersands = $rawAPIData.length() - $rawAPIData.replace("&", "").length())

## if there are no "&" at all then we have only one key value pair.
## we append an ampersand to the string so that we can tokenise it the same way as multiple kv pairs.
## the "empty" kv pair to the right of the ampersand will be ignored anyway.
#if ($countAmpersands == 0)
#set($rawPostData = $rawAPIData + "&")
#end

## now we tokenise using the ampersand(s)
#set($tokenisedAmpersand = $rawAPIData.split("&"))

## we set up a variable to hold the valid key value pairs
#set($tokenisedEquals = [])

## now we set up a loop to find the valid key value pairs, which must contain only one "="
#foreach( $kvPair in $tokenisedAmpersand )
#set($countEquals = $kvPair.length() - $kvPair.replace("=", "").length())
#if ($countEquals == 1)
#set($kvTokenised = $kvPair.split("="))
#if ($kvTokenised[0].length() > 0)
## we found a valid key value pair. add it to the list.
#set($devNull = $tokenisedEquals.add($kvPair))
#end
#end
#end

## next we set up our loop inside the output structure "{" and "}"
{
#foreach( $kvPair in $tokenisedEquals )
## finally we output the JSON for this pair and append a comma if this isn't the last pair
#set($kvTokenised = $kvPair.split("="))
"$util.urlDecode($kvTokenised[0])" : #if($kvTokenised[1].length() > 0)"$util.urlDecode($kvTokenised[1])"#{else}""#end#if( $foreach.hasNext ),#end
#end
}

Click the small tick to save these settings and select the Deploy API button.

In the popup box that follows select New stage and type prod into the Stage name box. Click Deploy to get your code live.

The URL

At the top of the page you should now be given a HTTPS URL (similar to https://xyz.execute-api.zone-1.amazonaws.com/prod).

To test this url type this into your command line (replace the URL with your own):

curl -H "Content-Type: application/x-www-form-encoded" -X POST -d '{"text":"mytext"}' https://xyz.execute-api.zone-1.amazonaws.com/prod

You should receive a response from your Lambda!

Phew…

You now have a Lambda with code to process your slash command, and an API to pass the data through. All that’s left is to link them together.

Go to https://slack.com/apps and click Build your own. Select Something just for my team from the next menu.

Select Slash Commands and give your command a name.

In the integration settings of your command enter the URL from Amazon into the URL box.

Test your command

In slack type /yourcommand some-data and you should see your code reply!

Where to go from here

All this code does is immediately respond to your command ignoring all the inputs. As long as you can reply within 3 seconds you can use the context.succeed function to return data immediately. If your code will take longer, you need to use the event.response_url to send data back to Slack when you have finished processing the data.

Amazon Lambdas have a maximum time of 5 minutes to run before they are stopped. The advantage of using them is you only pay when they are running (unlike a server which you pay for 24/7).

AWS has a free tier allowing you to get started straight away for free!

Further reading


Thanks to @brabster for the AWS proof-read.

Further reading: Slack API, https://medium.com/slack-developer-blog