Slack bots are fun, useful and easy to write! Here’s how you can write one yourself, in Go.
This is what our finished bot can do:
You need to have a Slack account (with enough privileges to create a bot), and know a bit of Go. Let’s start!
Go to https://YOURORG.slack.com/services/new/bot
and create a new Slack bot
by choosing a username (You’ll need to substitute YOURORG with your Slack
account’s domain). Copy the API Token from the next page, and save it
for later use.
At this point, you should be able to see the bot username in your Slack
client, in a logged out state. It joins #general
by default.
Now let’s get the mybot
code from github to hack on:
You should have the binary in $GOPATH/bin
after it completes. Run it to see
what it does:
mybot
now is ready to fetch you stock quotes as in the screenshot above.
Hit ^C when you’re done playing with it, and let’s see some code!
The Code
[Disclaimer: The mybot
code is meant for illustration only. It does not
have enough error checking/input sanitization code. Do NOT use it in
production.]
First up, we need to use the token to start a Real Time Message API session. We use the rtm.start API for this. As the documentation states, we need to pass the token to rtm.start, and it responds with a whole bunch of stuff. Thankfully, we only need a couple of things from this response.
Here’s how we make the call (file slack.go, method slackStart):
That performs an HTTP GET, reads the body of the response, and JSON-decodes
it into responseRtmStart
. Like we said, we only need a couple of things
from the response. The encoding/json
package’s Unmarshal
method conveniently
ignores extra fields in the input JSON object, which lets us define the
responseRtmStart
structure rather minimally:
The url
field in the response is a Websocket URL to which we can connect
to and start the RTM session. We also pick up the id
parameter, which is
the user ID of the bot, and looks like U1A2B3C4D
. We’ll need this later
to watch for mentions.
Using the Real Time Message API
Go’s “extra” libraries from golang.org/x
includes a websocket package:
golang.org/x/net/websocket
. It also includes a JSON codec that provides
wrappers for sending and receiving JSON objects over the websocket.
Starting a websocket connection using this package is easy (file slack.go, method slackConnect):
Over this connection, Slack notifies us of
nearly everything that happen in the chat rooms.
These notifications include messages posted by users into channels that mybot
is participating in, or sent as DMs to mybot
. These are the ones we are
interested in.
Each notification is a JSON object, having the common field “type”. The ones we are looking for have the value “message” for “type”. As before, we pick out the other relevant fields in these type of JSON objects using a struct (file slack.go):
To read these off the websocket connection, we use (file slack.go):
We can also post messages to a channel by writing a similar object back into the websocket. Note that there is no concept of replying to a message, you can only post messages into a channel. We need to supply a unique ID for each message we post, so we make use of an atomically incremented counter:
The Main Loop
With all this plumbing in place, we can write a main loop that looks like this (file main.go):
The bot will receive all messages, so we need to pick out only the ones that
mention the bot. Slack replaces all mentions of a user, with the string <@U1A2B3C4D>
(where U1A2B3C4D is the user ID of the mentioned user) in message texts. So,
a message like @mybot: stock goog
becomes <@U1A2B3C4D>: stock goog
. We
use this information to listen for mentions:
and to parse out relevant fields from the text:
For getting a quote and posting it, we use a goroutine, since we don’t want to block the websocket event loop:
Finally, the getQuote
method itself fetches the stock quote for the given
ticker using a Yahoo API. You should, of course, throw this out and replace
it with something useful and relevant to your team!
There are also other interesting things that the bot can do that we do not cover here.
Have fun building your own bot! Here are some useful links: