My New Favorite OS: Adventures with Slack Apps

DZone 's Guide to

My New Favorite OS: Adventures with Slack Apps

Creating the /Lunchbox app from scratch was an exciting opportunity for Nic Rosental and his team to get their hands dirty with Slack.

· Agile Zone ·
Free Resource

A few months ago, I decided to take dive deeper into Slack. As much as I love Slack for communicating between teams, clients, and offices at my agency 352 Inc., it’s also a new development platform – and I’m always on the lookout for a new sandbox to play in. After creating (and getting bored with) silly bots, I wanted to build an app that solved a real issue in the company: lunch outings.

Image title

Like any dev shop, we go out to lunch between head-down coding sessions. So, our Product Team and I got busy working on /Lunchbox – a simple, but powerful, Slack app to simplify organizing a lunch outing with colleagues.

Disclaimer: a few weeks after we launched /Lunchbox to the App Directory and started gaining dozens of outside users, Slack launched its own lunch app to highlight its brand new Message Buttons. Even though they stole our thunder a little bit, we’re really proud of the work you’ll see below (and we really like those dang buttons).

While /Lunchbox has made our daily lunch groups a much simpler exercise, it was also an exciting opportunity for me and a few other product developers to get our hands dirty with Slack. We quickly discovered why the good people at Slack view it as a full OS and not just another chat platform.

Before we explore the nerdy details of using the Slack API, this is a good opportunity to tell why we were so focused on building /Lunchbox. Earlier this year, we transformed our digital marketing teams into a product growth department, focused on bringing internal products like MixFrame (front-end folks, you’ll want to sign up for the beta) and PlanningPoker.com to market. We also want to launch five new products from this team in 2016; /Lunchbox is the first.

Fair warning: this will be a technical post full of development tips, but if you’re looking for detailed instructions on building for Slack, I recommend starting here.

As with any greenfield project, we had the luxury of choosing our technology stack with minimal constraints. We settled on the trusty MEAN stack due to how well-suited it is for real-time applications, the availability of high-quality packages for the Slack API, and our prior experience with the technologies involved. Other important tech bits were Gulp (with Nodemon) for our local development setup, Heroku for hosting, Git + Github for version control, and a few NodeJS modules – more on those later.

How Do Slack Integrations Work?

Our daily use gave us a vague idea of what the Slack API offers, but it was time to do a deep dive and really discover its capabilities. At present, Slack uses several distinct APIs that can be combined to accomplish complex integrations: webhooks, commands, RTM, Web API, and bot users. Once we understood what each of these offerings delivered, we decided our application would need commands and bot users.

Slack commands are easy enough, as most users know. A command phrase (preceded by a slash) triggers an action without showing the command: spam your channel with a storm of GIFs, check for certain data or give a shrug ¯\_(ツ)_/¯. In our case, we picked <code>/lunch</code>.

Bot users make Slack and its integrations tick. Bots can do pretty much everything a human user can do, which makes for a great opportunity to imbue the application with its own personality. We wanted our Lunchbox bot to be fun, but also useful.

By now we had picked our technologies, determined the APIs we needed, and decided how the application would work.

Putting the Pieces Together

The first step in a Slack integration is requesting permission. Slack uses OAuth 2.0. The implementation is very clean, and it’s made very easy with the use of the Slack Button.

Image title

Before requesting authorization, determine the scope of the permissions needed. Scopes can be broad or very detailed, but it’s important to make sure to understand which scopes are strictly needed and not ask for more than that. It’s poor form to be greedy, but it’ll also prevent you from getting listed in the Slack App Store. In our case, we settled on the bot and commands scopes, two broad options encompassing many other, smaller permissions.

Once a user adds the integration to their Slack team, the API responds with a JSON object:

        "team_id" : "T0XYZXYZX",
        "bot" : {
            "bot_access_token" : "xoxb-12345678900-1uDw3VvfRes2QaaRfc8EesWr",
            "bot_user_id" : "U0IDSE4T6"
        "team_name" : "352 Inc",
        "scope" : "identify,bot,commands",
        "access_token" : "xoxp-1234567890-1234567890-1234567890-8f3ed42f9o",
        "ok" : true

Store this information. Otherwise, the integration won’t be able to interact with Slack. Most of the items are self-explanatory, but I’d like to point out the <code>access_token</code>, and <code>bot_access_token</code>. The former is the authorization for the application itself to work with that particular Slack team, while the latter is exclusively for the bot user to perform actions such as posting a message to a chat, creating a channel, etc.

Image title

Now that the application has been authorized, the integration is live. In our case, we wanted to respond to the slash command /lunch. The initial step is to set up the command in our application dashboard. You’ll notice the Command editor is pretty straightforward.

Here we can enter the command to respond to, where the request is going to be sent to, a description and a usage hint. The usage hint is optional – we strongly suggest you include it. Bots are simple, but users will have an easier time using your integration with a little bit of UX focus.

Command Functions

While Commands are fairly easy to set up, you should know what’s going on behind the scenes. Once a user issues a command, all the data for that command gets sent formatted as JSON, via a POST request to the Request URL specified in the dashboard. This address must be SSL encrypted, and Slack must be able to reach it.

This represents a challenge when developing locally. Thankfully, there are excellent tunneling services that make setting this up dead simple. We picked Ngrok and it’s been rock solid. Start Ngrok by issuing a simple command like <code>./ngrok http localhost:5555</code> (where localhost:5555 is the address our NodeJS app is running on) and you’ll get a tunnel that serves your application through http and https to the world.

Image title

In this case, we could tell Slack to send requests to <code>https://cd986c3f.ngrok.io/commands/lunch</code>. Now that the tunnel is up and Slack knows where to submit requests, you can start building the bits that will receive, parse, and respond to the message.

In this example, the Midtown Atlanta user typed <code>/lunch at Cypress, F20 or Takorea at 12:30</code>. This is what you can expect to receive in your application’s endpoint:

Image title

In your Express app, you could set up a route like the following:

    app.post('/commands/lunch', function (req, res) {
        // do something with req.body here
        // send a reply to the channel
        res.send('Look, Ma! I can reply!');

The message "Look, Ma! I can reply!" will be sent back in what Slack calls an ephemeral message, which means it’s a message that only the user issuing the command can see. This is useful for sending error messages or responding to help requests. No need to publish those things to everyone in the channel.

If you don’t send a reply, at the very minimum an http status code, Slack will throw a timeout error, so make sure you don’t leave any unresponded endpoints.

Image title

Enter the Bot (Beep Boop)

Now that we have the command loop in place, we can bring the bot into the mix. In our case, we want to parse out restaurants – along with optional times and dates – from the command, build a message that offers one emoji per restaurant (for group voting), and then respond with the message asking people in the channel to join our lunch outing.

We won’t bore you with the details about parsing the message. Instead, we’ll go straight into the response. In this case, we don’t want to respond directly to the command, but instead, we want our bot to post the message as itself, and make it visible to everyone in the channel.

To make our lives easier, we decided to use the very simple Slackbots.js module.

The code for posting the message looks something like this:

    bot.postMessage(channelId, message).then(function(data){
        // do some other stuff here.
    }); </pre>

As you imagine, <code>then()</code> means a successful message. You can also work with <code>fail()</code> and <code>always()</code>. In this case, <code>data</code> contains the result of our successful message.

    { ok: true,
        channel: 'ABCD1234',
        ts: '1460488064.000030',
        { text: 'some message text that was sent by Lunchbox',
            username: 'lunchbox',
            bot_id: 'B01234AEVT',
            type: 'message',
            subtype: 'bot_message',
            ts: '1460488064.000030' } }</pre>

Our next step is to provide the reactions we want to use for people in the chatroom to vote. The key here is the <code>ts</code> entry. Messages in Slack use their timestamp as a unique identifier (as opposed to files, and file comments which have IDs).

To post a reaction to a message, we use the Web API endpoint <code>reactions.add</code>. In this case, we decided to use a simple http request and no libraries. This is entirely up to you, but it’s as simple as constructing the right URL and making a POST request to the endpoint. The following is an example of a URL that would send the :thumbsup: reaction to the message above.


Note that we are using the bot token ID, so the reaction will be posted by the bot user itself. This is useful so the person issuing the command can vote on the options without un-doing them.

At this point, we have all the building blocks that make the application work. Next, you’ll need to deploy it to a publicly accessible host. In our case, we chose Heroku. If you are using Heroku, you’ll want to work above the free tier plan. Otherwise, your app will go to sleep and users won’t be able to enjoy it.

Spreading the Love

We now had a nice integration for ourselves, but we definitely wanted to share our handywork with the rest of Slack world. The first step was to have our own website where users could learn about /Lunchbox, and also install it.

By default, any user can add an integration to their Slack team. The best way to enable them to do so is the Slack button. Of course, you’d need users to find you, and what better way to do so than having the app listed in Slack’s own App Directory.

The process of submitting the app for review was a breeze, and the Slack team was very fast and attentive throughout the process. In less than two weeks Lunchbox was listed in the App Directory and ready to schedule lunches the world over.

Build something cool, follow this checklist, and submit.

Wrapping Up

Given its wide use in dev shops and rapid adoption, it’s no surprise that the Slack API is so well constructed. Although we ran into some challenges at times (figuring out message IDs, working locally, etc.), we were able to quickly and easily overcome them and finish our application in a fairly short amount of time. Even though our victory party was spoiled just a bit by Slack launching its own lunch app, we’re still really proud of what we produced and the lessons we learned.

Are you ready for lunch? Check us out in the Slack App Store, and make sure you invite your colleagues.

Nic Rosental is a full stack web developer for digital product development agency 352 Inc. based in Atlanta. While he currently focuses on the front end, he is also well versed in server technologies and back-end programming. He arrived at 352 after running his own web shop, Epic Labs, for several years. Nic is an active member of the Atlanta web community. He acted as a co-organizer of AtlantaPHP for three years and is a regular speaker in the local conference circuit. Originally from Buenos Aires, Argentina, he arrived in Atlanta in late ‘99 and has since become a bona fide Southerner.

agile, api, slack, slack bots

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}