Building a Slack Chat Bot

Sending a Command

Jason Lengstorf

Jason Lengstorf

Learn With Jason
Building a Slack Chat Bot

Check out a free preview of the full Building a Slack Chat Bot course

The "Sending a Command" Lesson is part of the full, Building a Slack Chat Bot course featured in this preview video. Here's what you'd learn in this lesson:

Jason creates a function for handling the slash command from Slack. When the command is sent to the API, the handler validates the input and returns a message to Slack. Before the slash command can be run, the application must be added to the channel.


Transcript from the "Sending a Command" Lesson

>> The next thing that we're gonna do is we are going to send a command here. So let's get into the Slack utility, and we will import first "parse" from "querystring". Because "querystring" allows us to get a form-encoded body, or what exactly, I can't remember what it's called.

But it's where the key is set with an equal sign and then the value after that. And so this is gonna allow us to parse that out and actually use those values. Then we're going to import our slackApi command from the util that we just created. And we're gonna create a new function in here called handleSlashCommand, slash command, not slack.

My goodness, slash command. And that's gonna accept a payload, and the payload is a SlackSlashCommandPayload. And again, that's there so that we get autocomplete, not for any other real reason. So the way that I want this to work is to keep this kind of easy to debug later on we're putting the slash command logic into this function.

And then interactivity, which is a different functionality that we're gonna build later, will be in a separate function, and it'll help us with keeping track of kinda what's happening without having one big, long function. But I still want it to be scannable within the same file, so we'll keep them all in the same file.

We'll just have a few functions in there to help us separate things out a bit. So I'm gonna use a switch case, I know people have feelings about these, I think they're great for this particular type of setup. We are gonna look at what the command that came in is for our slash command, and then change the behavior based on what that command is.

So I'm gonna look for if the command is foodfight, then I want to get a response by awaiting the slackApi. And we're gonna use chat.postmessage. And you can see because we specified what the endpoint could be, it autocompletes for us. And that's really the only thing that keeps me using TypeScript, is I just I love that autocomplete.

So next we're gonna grab out of the payload we want the channel ID, so using the autocomplete to get there. The channel ID is also available if you look in your Slack instance, you can find the channel ID down here. That's so if you wanna always send the message to the same channel you can come and grab this and hard code it, as opposed to sending it to the channel where the message came from.

In this case, we're gonna send it back where the message came from. And then we wanna send in some text, and for now let's just do some hard coded text so that we can make sure this actually works. So we get a response, and then some really lightweight error checking here.

So if the response that comes back is not okay, we're gonna console log the response just so we can see what happened. And then we're gonna break out of our switch command. And then as a default we'll say just return a new status code, and that's gonna be a 200.

But we are going to say the Command payload.command. Is not recognized. So that way if somehow you were able to send a command here that isn't part of the registered commands you'll get a note that it doesn't work, something is wrong. To actually use this, we are going to grab the event that gets sent in through the Netlify functions, this gives us access to things like what the payload is.

And then I'm going to handle the slash commands by grabbing the body. So the body is going to be, we're gonna use that parse and get event.body, or we'll just make it 0. And then I'm gonna coerce it to be a slack payload because I want that autocomplete again.

And we'll be able to validate that this is a Slack payload when we get to this part where we're actually validating requests. But for now, we just want that to work the way that we expect it to work. And then we are going to check if body.command. Then we want to return handleSlashCommand, and we're gonna put in the body as a SlackSlashCommand.

And that is gonna be the whole thing, right, because it's going to return. I forgot a piece. Because we have our default here where we're returning. But we also wanna make sure that at the end, we return a status code or an object, sorry, that's got a status code of 200 and a body that's just empty.

So if it's successful, we don't need to send anything back because the chat message will appear. If it's not successful, we want to give some feedback to just the person who ran the command to let them know like, hey, your command didn't work. So in this case we will just do this here and send a 200 as kind of a confirmation that the command worked.

If we don't send this, then Slack will time out and say something went wrong. So now we've got this set up and running, and let's actually try it. So I'm gonna run a food fight, And it didn't like it. Here we go, we got an error, not in channel.

Ah-ha, so that means that our bot has to be added to the channel before we can actually use it. So let's add apps to channel, and then I'm gonna grab this food fight. I'm gonna show what I did there cuz I just kinda did that fast. But I started typing add and it shows this context menu of add apps to channel, so grab that.

And then here's the bot, I'm gonna add it, and now food fight has been added to this channel. And this will need to be done for any channel where you want the bot to work. Typically speaking, what I've done is for my teams I have the bot run almost exclusively in my team's channel.

But for some things like the context reminders if somebody's posting requests all over the place, you might wanna install it to the entire workspace, which you can do. There's some ways that you can have the bot auto add itself if you give it that permission. And we're not gonna cover that today because I don't think it's necessary unless you've got extenuating circumstances.

But otherwise, just add it in any channel where you wanna use it. And now if we run Food Fight again, there it goes. This is posted publicly from the Food Fight app as a chat message. So that's the kind of first major takeaway here, is how to get a bot to post to your Slack channel.

And this can be done outside of a Slack command, or out of a slash command. You can have the bot post to your channel at any time, which is how we'll do the cron job later on. But using a slash command to post some feedback as the bot is a great way to just make it feel like part of the experience.

I am asking a question in the channel, and the bot gives me feedback on the thing that I've asked. That feels the exact same as if it was a member of the team, but now it's more consistent and it's built into the process. Even at this point, a slash command is really, really useful without building anything else.

Because you can use this to say slash open issues, and then you can go hit the GitHub API and pull every open issue for repos that your team is responsible for. You can make API requests in between getting the slash command and sending that chat response, right? So you can do just about anything here, and that's really, really powerful.

So to actually show how this works, let's just really quickly put in something that won't stick. We're just gonna play with it for a minute, and I'm going to add a joke in here. So let's get a joke, and that's going to be the output of a fetch command that will go to, which just gives you a random dad joke.

And that will use headers, and we just wanna return the accept header of text plain. Because we're not gonna parse the JSON object, we just want it to send us back a plain old joke. So then, in our response here, we can use the await joke.text to get that response as plain text.

And so this could be, you can imagine, kind of anything, right? I can call anything that's got an API endpoint, I can grab, and then if I wanted to I could do far more parsing on the JSON object or anything else to then return this in the chat message.

But for now if I go and use this, anytime you run this it's going to give you a new dad joke. So it's a very nice workflow in chat if there's something you need to check all the time. Rather than saying yeah, let me go check that for you, and getting out of your flow, moving into some dashboard somewhere, and then coming back and copy pasting a screenshot.

You can take a little bit of time to put together one of these slash commands and just say status, and have it print that screenshot right there for you. Or give you the top stats for whatever thing, find out who's on call. Whatever the things are that you find yourself checking frequently in your team, you're able to do that with a slash command very quickly.

And this is the power of that ChatOps workflow, is you can really cut down on the amount of time you spend context switching to grab information that's available via api anyways.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now