Today I would like to show you how to build Slack Bot using serverless approach on AWS infrastructure. We are going to support our efforts using AWS Chalice framework. Our Slack Bot is going to be a dummy one. It will respond with a message we send to it. However this article is not about implementing sophisticated bot behavior. We want to setup whole stack which will be a foundation for further development.
AWS lambda in chatbot context
“Why should I use AWS lambda to implement chatbot?” you might ask. Well, chatbots respond to events. Each event could be a message sent by a human being, or it could be a scheduled action which triggers sending a message to human beings without being asked. AWS Lambda is an ideal case for it as is supports both cases.
AWS infrastructure and Chalice framework
Chalice is a framework developed by AWS which helps writing serverless REST APIs. It is similar to Flask. The main advantage of Chalice is that we focus on writing Python code, which represents our API. Chalice handles deployment to AWS Lambda and API Gateway for us. It also has handy features like local development, printing API URL, deleting whole stack etc.
Thanks to Chalice, we will not touch AWS CLI nor AWS web console. However in this blog post, I assumed that you already have AWS account and you have your AWS CLI set. Chalice will use it indirectly. If you do not have it, please follow this tutorial in order to set it up.
Proposed AWS solution
How our solution is going to work:
- Task#1 Slack Bot definition using Slack UI
- Task#2 AWS infrastructure definition using AWS Chalice framework
Step #1: Slack Bot definition
At the very beginning we need to define our Slack Bot. It’s custom thing so it can be found under Customize Slack option in Slack main menu.
OAuth & Permissionsyou have to click
Install App to Workspace. This will generate an unique token which will be used by the lambda.
Bot User OAuth Access Tokenwhich can be found inside
OAuth & Permissionssection:
Bot User OAuth Access Tokenwill be used in the next step.
Step #2: AWS Chalice code
Virtual environment preparation
Let’s prepare our Python3 dev environment using virtualenv for Chalice and AWS Lambda:
> mkdir benderbot > cd benderbot > virtualenv --python $(which python3) venv > source venv/bin/activate > pip install chalice > chalice new-project benderbot > cd benderbot
import urllib from chalice import Chalice app = Chalice(app_name='benderbot') app.debug = True BOT_OAUTH_TOKEN = "xoxb-048444305-....set_your_token_as_this_const" @app.route('/', methods=['POST']) def event_handler(): request = app.current_request if "challenge" in request.json_body: return request.json_body["challenge"] slack_event = request.json_body['event'] if "bot_id" in slack_event: logging.warn("Ignore integration bot message") else: text = slack_event["text"] response = "Bender says: " + text respond(response, slack_event) return "200 OK" def respond(response, slack_event): channel_id = slack_event["channel"] data = urllib.parse.urlencode( ( ("token", BOT_OAUTH_TOKEN), ("channel", channel_id), ("text", response) ) ) data = data.encode("ascii") request = urllib.request.Request( "https://slack.com/api/chat.postMessage", data=data, method="POST" ) request.add_header( "Content-Type", "application/x-www-form-urlencoded" ) urllib.request.urlopen(request).read()
Let’s break our solution down into smaller pieces:
import urllib from chalice import Chalice app = Chalice(app_name='benderbot') app.debug = True
Besides boring imports, we define Chalice app and enable debugging. We will not debug our solution in this tutorial but you may want to do this during some feature development. I have used it here for reference.
BOT_OAUTH_TOKEN = "xoxb-048444305-....set_your_token_as_this_const"
I skipped obvious parts as method definition and extracting current request. Pretty interesting part is the following one:
if "challenge" in request.json_body: return request.json_body["challenge"]
if "bot_id" in slack_event: logging.warn("Ignore integration bot message")
Warning: if you omit this part, your slack bot will respond to its own messages. It will fire a recursive loop of lambda calls.
text = slack_event["text"] response = "Bender says: " + text respond(response, slack_event)
respondmethod itself are self explaining. We are sending simple HTTP request to Slack API.
OK so at this point we have our simple bot implemented. Now it is time to deploy it to the cloud:
> chalice deploy Creating deployment package. Updating policy for IAM role: benderbot-dev Creating lambda function: benderbot-dev Creating Rest API Resources deployed: - Lambda ARN: arn:aws:lambda:us-east-1:<our_account_id>:function:benderbot-dev - Rest API URL: https://jqjrwn2kpd.execute-api.us-east-1.amazonaws.com
> chalice url https://jqjrwn2kp.execute-api.us-east-1.amazonaws.com/api/
Step #3: Connecting AWS with Slack API
In the first step, we defined our Slack Bot in Slack web UI. Then, in step 2, we implemented bot and deployed it into AWS Gateway and Lambda. Now it’s time to make those two talk to each other.
We need to enable events which will be sent to our Lambda code. Back in Slack web UI select
Event Subscriptions and enable events:
Request URLyou should paste output from
chalice urlcommand. After you paste it, the green mark should indicate that you setup everything correctly.
Now it’s time to setup events. We’ll instruct Slack to send events to API Gateway. In our case, those will be direct messages. As an event select
message.im and save changes:
Bonus: advanced monitoring
We used following statement in our code:
app.debug = True
Now go and write some bots!
Make ChatOps and DevOps a Competetive Advantage of Your Business
ChatOps and Serverless are our core expertise. Partner with our experienced and pragmatic builders that help you innovate move quickly and be cost-effective with use of cloud platform and chatbots.Schedule a call with our expert