Build Slack Home Tab in minutes using AWS Lambda and Amazon EventBridge
When we built the first version of Vacation Tracker, UI for Slack integrations was very limited. You could make your integration interactive by mixing buttons and dropdowns. Luckily, a limited number of interactive elements combined with a grain of imagination lead to countless creative ideas. Not all of them provided the best user experience for our users, but they were way better than our biggest competitor – the big bad spreadsheet.
The first version of our product was similar to the following image. We improvised a calendar using simple buttons. No weekends? The limit was five buttons in a row. It’s a leave-tracking app, who works during the weekends anyway? Many people, as we learned quickly.
Slack improved a lot in the last two years. They added a date picker, modals, input fields, and many other useful UI elements. Besides that, Slack improved its permission scopes, which was very important for Vacation Tracker, because we tried to know just a few most basic things about our users.
Our product was better than ever as one of our latest feedbacks says it’s super easy to use, much better than submitting paper forms. Managing your leave days is just one Slack command away.
However, not all of our users know how to use slash commands. Was it slash (“/”) vacation, hashtag vacation, or some other weird character?
Wouldn’t it be nice if we could have a place in Slack where users can find everything they need to know about Vacation Tracker? Something like a simple dashboard. Fortunately, someone at Slack thought the same.
Slack App Home tab
At the end of 2019, Slack introduced the Slack app toolkit. This toolkit is essential because it brought a better way to manage permissions, Block Kit, a new Slack UI framework, and — App Home tab!
An App Home is a private, one-to-one space shared by the user and the app. The user can reach the App Home from the conversation list within Slack or by clicking on the app’s name in messages.
An App Home is dynamic. We can use an App Home and Block Kit to show all critical information from Vacation Tracker to our users just in time. Even if our users do not know how to use slash commands, they’ll be able to request leaves directly from Slack by clicking the button in the Home tab.
It sounds like a significant improvement for our UX! Where do we start?
How does App Home tab work
To add an App Home page, you need to request the necessary permissions and enable the home tab for your app, as explained in the Slack guide here.
You also need to create a Slack application and install it in your workspace, which is beyond the scope of this article, but many other guides cover it.
When your Slack integration is ready, you can show the UI on the home tab by sending an array of blocks to the
views.publish Web API method. You can see more details about this API method and supported blocks by visiting an official Slack guide.
As the App Home tab is private and can be unique for each user, besides the blocks and the bot token, the
views.publish Web API method requires an ID of the users that interacts with the Home tab. You can get IDs of all users from your database or from Slack’s Web API.
The other and probably better way to deal with the App Home tab is just in time. When a user opens an App Home tab, Slack sends the
app_home_opened event. You can set up a webhook to receive the
app_home_opened event, and publish or update an App Home tab for that specific user. This event contains a user ID, and you need to provide your new blocks and a valid bot token.
Making Slack integrations painless and scalable
We wrote about the way we use Amazon Web Services (AWS) and serverless architecture to build our product and Slack integration. You can read some of our articles about serverless and the technology behind Vacation Tracker here and here on our blog, or in a few external sources, such as the AWS blog, and other websites. In case you are not familiar with serverless, you can take a look at one of the linked articles for more info.
We use serverless and AWS to make our product and Slack integration scalable with a minimal amount of maintenance. Most of the time, Slack requires an answer from our system within three seconds, which is a long time if you do not have to parse an event, do a complex calculation, and also add a couple of hundred milliseconds of network latency and cold start. Fortunately, our cold start is less than 200ms because we use small Node.js modules. If you face a higher cold start latency, you might want to take a look at AWS Lambda Provisioned Concurrency.
Our initial architecture was similar to the following diagram. We connected all Slack webhooks to our API Gateway. The API Gateway then triggers different Lambda functions for different types of Slack integration (events, slash commands, or dialogs). Each of these functions parses the Slack messages, publish them to our Amazon Simple Notification Service (SNS) topic, and responds to Slack with a 200 OK status. Then the SNS topic triggers other Lambda functions that do the business logic.
The architecture looks simple. However, the red square has nothing to do with our business logic and Vacation Tracker. These services would work the same for any Slack integration. Our philosophy is to try to outsource everything that is not part of our business logic. Unfortunately, there’s no simple service that would outsource this Slack integration in the way we need it, so we built one.
We already wrote about creating a serverless application that handles generic webhooks, and you can read about our journey and approach here. This solution does not work for Slack integration, because some of the webhooks need to answer verification requests. Also, Slack sends some payloads as JSONs, some are URL encoded, but when you click on a button in Slack integration, Slack sends an URL-encoded payload that contains stringified JSON. Our generic webhook handler is not able to unpack all of these specific payloads.
We decided to create another AWS Serverless Application Repository (SAR) application that handles Slack-specific webhooks and provides an easy way for us to build new Slack integrations without thinking about parsing events and responding to Slack.
To learn more about SAR, read our previous article about the generic webhook handler here. To learn more about building and publishing serverless apps on SAR, see this excellent article.
As you can see in the following diagram, the architecture of our new integration looks similar to our initial architecture. However, there are two crucial differences: our SAR application hides webhook and event processing, and we replaced Amazon SNS with Amazon EventBridge. The EventBridge is a new service that brings a fully managed enterprise service bus to an AWS serverless offering. You can publish all the events there and then subscribe to your Lambda functions to one or multiple events containing a specific parameter. For example, you can trigger a specific function when the user opens a Slack Home Tab!
Let’s dive into the most exciting part of this article – the code.
Using our new serverless application
The easiest way to demonstrate the way our new SAR app works is to build something. So let’s build a simple to-do list that looks similar to the following mockup.
To use our new serverless application, you need an active AWS account and basic knowledge of serverless and AWS Serverless Application Model (SAM). These prerequisites are beyond the scope of this article, but many online resources can teach you the basics of serverless and SAM. If you prefer books, you can check the excellent Running Serverless book, written by Gojko Adzic.
Once you setup all prerequisites, initialize a new SAM application with the
node12.x runtime. And open your
If you are using the new
sam deploy --guided command, deploy the application once before modifying your
template.yaml file. Then open the
samconfig.toml file, and replace the following line:
capabilities = "CAPABILITY_IAM"
With the following configuration:
capabilities = "CAPABILITY_IAM CAPABILITY_AUTO_EXPAND"
This “CAPABILITY_AUTO_EXPAND” capability allows you to install SAR applications using SAM.
template.yaml file to look similar to the following code sample:
The previous code sample will setup the basics of your serverless application. This template does the following:
- It tells Amazon CloudFormation, the beast behind AWS SAM, that you want SAM to take over.
- It passes the two parameters to your SAM app:
EventBusName– tells SAM how to name your event bus, “SampleSlackEventBus” is a decent name.
BotToken– tells your app which bot token to use. In production, you probably want to get this from the API, but for a sample app you can pass a value from the “Install App” tab of your Slack App settings
- It sets the function’s global configuration, so you don’t need to repeat that in each of your functions.
- It defines resources, which we’ll do in a few minutes.
- It defines an output, which is a webhook you can use for Slack integration.
Another warning for the new
sam deploy --guided command users: Remember to add the “parameter_overrides” values to your samconfig.toml file. To do so, replace the existing “parameter_overrides” value with something similar to the following code sample:
parameter_overrides = "EventBusName=EVENT_BUS_NAME BotToken=xoxb-YOUR-BOT-TOKEN"
EVENT_BUS_NAME placeholder with your event bus name, and the
xoxb-YOUR-BOT-TOKEN placeholder with a valid bot token for your Slack app.
The next step is the installation of our new SAR app. To do that, add the following code to the Resources section of your
This code sample creates an EventBridge event bus and uses the value of the variable you provided as an event bus name. And it installs our SAR application. At the moment of writing, the current version of our app was 1.1.0, but you should use the latest version from SAR or our GitHub repository.
Now you have everything you need to start handling the events. The first event we want to handle is the opening of the App Home tab. Add the following Lambda function to the resources section of your template.yaml file.
Let’s go through this code sample line by line:
SlackHomeTabrepresents the name of your Lambda function. You can change this, but try to make it descriptive.
Type: AWS::Serverless::Functiontells SAM that you want to add a Lambda function.
Propertiesdefine a list of properties for your function.
CodeUri: build/home-tabtells SAM to take the app code from the “home-tab” folder, located in the “build” folder. We use TypeScript for our Lambda functions if your source code is in some other location change this line.
Handler: lambda.handlertells SAM that we exported
handlerfunction from the lambda.js file. Change this value if your function or the file are named differrently.
Environmentsection defines environment variables. We do not want to hardcode our bot token, so we pass it as the
BOT_TOKENenvironment variable in this section.
Eventssection defines an event that triggers your Lambda function.
And now we came to the most exciting part of the code. See the following code example:
This pattern tells an EventBridge event bus to trigger this specific function if the event contains the following structure:
Our SAR application, in combination with the EventBridge, makes a powerful but easy-to-use library for Slack integrations. Besides specific events, you can target a specific slash command or even click on a specific button in your Slack app.
To add another Lambda function that triggers on click on the “Add todo” button, you can add the following code snippet to the resources section of your
As you can see, the only difference is the event pattern. Slack buttons send a payload that contains actions. If one of the actions has the “add_todo” value, EventBridge invokes this function.
Modal submission is just another event, and you can handle it by adding the following code to the resources section of your
Now you need to write code for your functions. If you want to see everything in action, feel free to use the code from our sample GitHub repository.
When you pull the code from our repository, run the
npm install command to install the dependencies. Then run the
npm run build command to build the TypeScript code. And finally, run the
sam deploy command to deploy the application.
The deployment should output the webhook URL. Set this URL as a webhook URL in the “Event Subscriptions” and the “Interactive Components” sections in your Slack application settings.
The result should look similar to the following gif:
Not bad for a few minutes of coding!
Next steps and architecture evolution
This architecture gives you a simple but flexible and scalable architecture for your Slack integrations. By default, your integration can handle up to 1000 parallel requests. You can increase this number via AWS support. It gets even better; you are charged per usage. If no one uses your Slack integration, the infrastructure is free.
As a next step, you should add a database that would store bot tokens and other user preferences. We recommend using DynamoDB, AWS database that scales automatically and is an excellent fit for a serverless application.
You can also subscribe to our newsletter if you want to get articles similar to this one directly in your inbox.
Now, go and build something amazing! Keep an eye on the Vacation Tracker Home tab, which we’ll roll out to our users in the following few days.
CTO and co-founder of Vacation Tracker, AWS Serverless Hero, and co-author of Serverless Applications with Node.js, published by Manning Publications.