Do you know what happens when you type/giphy sorry no can do
in one of your Slack channels? A funny gif pops up, so instead of explaining to your teammates why a particular task will require a bit more work than anticipated, you let them know by sending this:
That is, in short, what a Slack bot does.
It’s been some time since I became interested in Elixir and I finally decided to do something fun with it on my way to mastering it. I went with creating a small Slack bot with slash commands and I’ll show you how to make your own in a short tutorial I compiled below.
Let’s get to it.
One caveat before we start—this tutorial is just a proof of concept as I’ve never either:
- used the Slack API before,
- deployed anything with Elixir.
So, how to build a Slack bot step by step? Well, we want to:
- create a simple REST API with Elixir to accept commands from Slack,
- deploy it,
- create a Slack app with a slash command communicating with the Elixir API,
- introduce the app to the team and test the connection.
REST API with Elixir
We’ll just create an app with a single “hello world” endpoint.
mix new slackolixir --sup
creates a new Elixir project with a supervision tree. Supervision is a more advanced topic (one I still haven’t dived into yet) that requires deeper knowledge of Elixir’s processes. After all, “in Elixir, all code runs inside processes.”
The first file of interest is mix.exs
, especially the private method deps
. This is where we define our project’s dependencies.
We need two to make this work:
defp deps do
[
{:plug_cowboy, "~> 2.0"},
{:jason, "~> 1.1"},
]
end
By way of explanation— plug
is our connection adapter, cowboy
is our HTTP server, and jason
is a JSON parser. Running mix deps.get
in the console downloads those dependencies to our project (note that the mix.lock
file is updated).
Now, we’ll use Plug to create our simplest router. Create thelib/slackolixir/router.ex
file:
defmodule Slackolixir.Router do
use Plug.Router
plug :match
plug Plug.Parsers, parsers: [:json, :urlencoded], json_decoder: Jason
plug :dispatch
post "/hello" do
send_resp(conn, 200, "world")
end
match _ do
send_resp(conn, 404, "not found")
end
end
From the Plug docs:
The router is a plug. Not only that: it contains its own plug pipeline too. The example above says that when the router is invoked, it will invoke the:match
plug, represented by a local (imported) match/2
function, and then call the :dispatch
plug which will execute the matched code.
We are using the POST endpoint, because that’s the kind of request the Slack API will use when sending slash commands. We’re also adding:urlendcoded
to the parsers, as that’s the Content-type
header sent by Slack.
We still need one more thing for this to start responding—namely to add the server to our supervision tree. There’s a singlestart
method inlib/slackolixir/application.ex
.The generated comments should be enough to explain what’s going on for the purpose of this tutorial. What we need to do now is to incorporate the Cowboy server process into our Router in achildren
list.
children = [
{Plug.Cowboy, scheme: :http, plug: Slackolixir.Router, options: [port: 4000]},
]
Let’s test it locally, shall we? You can get the server running mix run --no-halt.
Note that our app is compiled first. Now try to make aPOST
request tolocalhost:4000/hello
(I’m using Postman). The response should beworld.
Congrats!
Deployment using Gigalixir
At the risk of oversimplifying things, we might say that Gigalixir is Heroku for Elixir apps. The simplest pricing plan is free. Perfect! For now, we need to create an account, create an instance through the dashboard, and go back.
The minimum setup we must perform before deployment is to specify the Elixir version we’re using (1.8 in my case).
touch elixir_buildpack.config
echo "elixir_version=1.8" > elixir_buildpack.config
That’s it! In the Gigalixir dashboard, you’ll find a short guide on how to deploy your app. Just add a proper git remote, commit your changes, and push! We won’t provide any add-ons (like a database) for now. It’s also useful to get Gigalixir’s CLI to perform actions such as checking the logs of our app.
One more thing to remember: by default, Gigalixir will try to check the health of your app on port 4000—but we got it covered because we already set it up in the Cowboy server process.
If everything worked as intended, you should be able to make a POST request to your app’s addresshttps://your-generated-url.gigalixirapp.com/hello
through Postman.
Creating a Slack app
The requirement here is to have a Slack workspace created. You can create new apps under https://api.slack.com/apps. Once there, navigate to Slash Commands on the left panel. Click Create New Command. You should see the screen below:
Command is, well, the command you will use in Slack channels to communicate with the Elixir server. Request URL is the full API URL for the command—in this simple case it’shttps://your-generated-url.gigalixirapp.com/hello.
Add a short description to your command in the appropriate field and you’re good to go. The preview below will animate everything as you type so you can see how it’s going to look in the channel.
Now, go back to Basic Information in the left panel and choose “Install your app to your workspace.” Accept the terms and... you’re done!
You can open Slack, choose any channel in that workspace, and run your command.
Summary
What we have here is not exactly usable yet, but we already have most of the mundane work behind us. We’ve managed to lay a good foundation for our subsequent efforts.
I’ll try to come up with a good idea for another useful Slack app and will be back with a more in-depth story on how to add more endpoints, persistence, and validations.
In the meantime, if you’re interested in Elixir, dive into our top articles on the topic: