Web Development

How to Build a Slack App Using the Slack Bolt Framework

Eric Izazaga
Eric Izazaga
3 minutes
Featured Image for How to build a Slack app using the Slack bolt framework

A few months back, I set out on a project to improve our company’s service request intake process. The goal was to create an app where our customers could submit service requests as well as view their requests from our Jira’s in-progress board. As a software company whose clients are also in the software industry, Slack is a common form of communication between our employees and our customers. We realized that building a Slack app would be the most extensible and efficient way to provide our clients with a ticket request service.

Why We Built a Slack App

Think of the classic game of telephone where an original message gets whispered from one person to another. More often than not, the message gets distorted along the way. By providing a Slack app to handle our service request intake, our employees don’t have to worry about notifying the correct project manager or translating technical details to developers. The client now has all of the responsibility of communicating their needs, and our project managers can sift through requests, assigning tasks to the right employees.

Build Using the Slack Bolt Framework

For the most part, setting up a slack app is straightforward, but there were some major hurdles that I aim to clarify in hopes of helping you get started on your Slack app. For our app, I used the Slack Bolt framework, which I believe does an excellent job of cleaning up Slack’s web API despite having some limitations and drawbacks of its own—I’ll touch on these later.

A Quick Rule of Thumb on Authentication

The first step in building a Slack app, as is the case with other platform builds, is to set up authentication for users. If your app will only be installed in your workspace (for your employees), then you can skip authentication entirely. If, however, you want to publish your app or make it accessible to other workspaces, then you’ll need to authenticate the user and their workspace, and identify their bot token for your app to communicate with them. If you’re building with Bolt and plan to release the app to other workspaces, I suggest starting by creating the functionality for the storeInstallation and fetchInstallation methods that the app’s initialization uses (excuse the developer jargon if you’re not familiar with it). The fetchInstallation uses Bolt’s InstallQuery object, giving you access to identify a user or workspace with the app’s initialization. StoreInstallation should simply add new users to your database using the same InstallQuery payload and can be as simple as a single line of code:

return await database.ref('workspaces').push({ team_id: installation.team.id, installation })

The Last Piece to your Authorization Method

The last piece to the workflow is the authorize method, which I assumed was already built-in and defined by Bolt where developers simply had to invoke it. I realized, however, that I had to define the function then discover what its intention was. My authorize function simply calls the fetchTeam function that I wrote for the fetchInstallation method using a teamId parameter to look for and return the workspace in our database that matches the Id. I invoke this function whenever my app interacts with the user to get relevant information regarding the user and his or her channel. Other than those few functions, you can directly copy and paste Bolt’s initialization code into your app and hit the ground running. As I mentioned previously, if you’re building an app solely for use within your workspace, you can skip these steps altogether and start building out the functionality of your new slack app.

Choosing your Slack App’s Slash Command

When building a slack app, you’ll create your slash command or Slack’s rendition of the “#” for invoking functions on its platform. Once your app is initialized, setting up your slash command is as simple as defining the function name (ours is “/webstacks”) on Slack’s dashboard and creating an endpoint in your app that “listens” for the function to be called. Our app responds with a greeting addressing the user by name and four buttons, each representing a different way the user can interact with the app. By calling the authorize function inside the slash command listener, I’m able to access the user token unique to the user’s workspace and pass it into Slack’s client.users.info method to retrieve the specific user’s information—Name, email, etc.

How our Slack App Functions in our Workflow

Depending on the next interaction, we may or may not need to call the authorized function again. For example, if you want to simply return views to the user, which are visual blocks of images, information, etc., you can do so without invoking the authorize function until and unless it culminates in an action that your app listens to, like a button click. For our app, when a user wants to submit a new service request, they first click a button returned from our slash command which does not call the authorize function. The event listener for the button simply returns a new view with a form for the customer to fill out with their request’s information. When they click submit, however, that button’s event listener again fires off the authorize method to identify and associate the user submitting the request with the correct company in Jira.

Something to Look Out for

The difference between opening and submitting views as described above is an excellent example of the nuances of Slack’s functionality and led me to a very perplexing issue where users’ data was getting mixed up with other users’ data between app interactions. Users from Company A were getting tickets from Company B, while User B was getting addressed as User A. I had presumed that interactions were chained to preserve a web socket-like connection between users and the app. However, that’s not the case. While some interactions like the chaining of views can persist information from one interaction to the next, other actions like button clicks are completely independent of the rest and must be treated as the first interaction between the user and the app—Users must invoke the authenticate method.

Yes—Our Slack App Caused Some Painpoints

Getting Around Bolt’s Restrictions

As I mentioned earlier, Bolt has some restrictions. We wanted our response to have the appearance of Slack attachments where the sidebar’s color distinguishes the service requests by the priority level. Attachments didn’t seem to be possible using Bolt’s respond or say methods, but I was able to get the attachment object to work using the web API’s chat.postMessage method. This is a simple tradeoff but an example of one of several instances I felt that I tried everything in Slack’s web API to overcome Bolt’s shortcomings.

Slack-app-in-action

Working with Slack’s block builder similarly takes a considerable amount of tinkering to get things to work how you might imagine, but, as with all things in development, persistence pays off.

Setting Up Custom Endpoints for 3rd-Party Services

The last major obstacle I encountered was setting up custom endpoints for third-party services. All endpoints that I set up were event listeners or auth endpoints that were part of the Bolt framework. Our app creates tickets in HubSpot and Jira and listens to webhooks from one to interact with the other. The app sends our customers updates when tickets have been marked as complete. No matter what I tried, I couldn’t get Bolt’s custom express receiver to access the incoming information from the webhooks coming in from HubSpot and Jira. I finally found a workaround by declaring express as you would for a normal express app then passing the body-parser declaration into Bolt’s express receiver:

receiver.router.use(express.json())

The two lines of code were simple enough, but the issue was a real blocker and is something that should be and was not defined in Slack’s documentation when I built our app.  

Implementing your Slack App into your Workflow

With our web services communicating together within our app and our data finally persisting correctly between a user’s interactions, the last thing to do was to release our app. Slack provides a very simple way to do this with an “Add to Slack” script that you can simply paste onto an HTML page hosted by your web app. If we share the link to the webpage, users can click the button which fires off the OAuth process for new users and workspaces to access our app. The OAuth process is like most others in that our endpoint receives and extracts an access token that is sent when the user clicks the “Add to Slack” button then attaches it to a query string that our app sends back to Slack. If everything works as it should, we get a green light from the response, redirect the user to a “success” page, and store the response data as a new workspace in our database. The most important step in this process is to assure you correctly line up the URLs in your Slack’s configuration with the endpoints in your web app.  

Overview on Building a Slack App

I reached out to Slack on several instances to discuss some of the problems I was running into. Unfortunately, they don’t look at code, so you need to articulate your problem well enough for them to be able to comprehend where things may be going wrong for them to provide meaningful insight or guidance. Their quick response time and willingness to dive into issues were very much appreciated. I will say this—Be prepared to end up in a dead-end when searching for third-party documentation or community resources when you run into problems. But it only adds more of an incentive to find a solution and build what could be a valuable asset to your team. I may be biased, but as a developer who gets jazzed by integrations and automation, I strongly believe the time and cost involved in setting up a Slack app are valuable in the long run. The fun alone in developing your Slack app makes it worth the time and strain of learning how to build on Slack’s platform. Again, as a developer, I may be biased.  

Share This
Table of contents
Why We Built a Slack App
Build Using the Slack Bolt Framework
A Quick Rule of Thumb on Authentication
The Last Piece to your Authorization Method
Choosing your Slack App’s Slash Command
How our Slack App Functions in our Workflow
Something to Look Out for
Yes—Our Slack App Caused Some Painpoints
Getting Around Bolt’s Restrictions
Setting Up Custom Endpoints for 3rd-Party Services
Implementing your Slack App into your Workflow
Overview on Building a Slack App