How to Create a Bot in Slack with Elixir Phoenix?

Mateusz Karbowiak

slackbot-1

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:

a gif with a girl saying: No can do comrade

 

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:

  1. used the Slack API before,
  2. deployed anything with Elixir.

So, how to build a Slack bot step by step? Well, we want to:

  1. create a simple REST API with Elixir to accept commands from Slack,
  2. deploy it,
  3. create a Slack app with a slash command communicating with the Elixir API,
  4. 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.exfile:


    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/2function, 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:urlendcodedto the parsers, as that’s the Content-typeheader 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 singlestartmethod 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 achildrenlist.


 
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 aPOSTrequest 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/hellothrough 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:

 

Creating commands in a Slack app

 

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.

command hello - test
Slackbot test - hello world

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:

  1. How We Learned Elixir—Our Story and Tutorial for Beginners
  2. We’re All Going To Meet In The Elixir World
  3. Why choose Elixir?
Mateusz Karbowiak avatar
Mateusz Karbowiak