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!
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!
mybot code is meant for illustration only. It does not
have enough error checking/input sanitization code. Do NOT use it in
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
responseRtmStart. Like we said, we only need a couple of things
from the response. The
Unmarshal method conveniently
ignores extra fields in the input JSON object, which lets us define the
responseRtmStart structure rather minimally:
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
is participating in, or sent as DMs to
mybot. These are the ones we are
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
(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:
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: