次のGIF画像のような、メンションに反応して選択肢を表示、そのあと選択に応じた処理をしてくれる BOT を作ります。
いわゆる ChatOps 的な使い方ができそうなやつです。
全体の流れ
Slack の3つの機能を使っているため、ここをちゃんと分割して考えることができれば、理解がしやすくなります。
- ユーザーからのメンションを受け取る部分 (Event Subscriptions)
- チャンネルへメッセージを投稿する部分 (Slack API)
- 選んだ選択肢を受け取る部分 (Interactive Components)
Cloud Functions の準備
Slack App から来るイベントを受け取るための HTTP サーバーとして Google Cloud Platform の Cloud Functions を使います。
Event Subscriptions の受け取り先になるには、そのサーバーを所有していることを証明する必要があり、 url_verification と呼ばれてます。
簡単にまとめると、challenge
という値がリクエストに含まれて来るので、その challenge
をそのまま返せばOKです。
さっそく app.js
というファイルを作って、満たす関数をつくってみましょう。
const onRequest = (req, res) => {
const payload = req.body;
if (payload.type === 'url_verification') {
return res.status(200).json({ 'challenge': payload.challenge });
}
res.status(200).send('OK');
}
exports.slackChoicesBot = onRequest;
書き終わったら、gcloud コマンドですぐにデプロイできます。 (最近東京リージョンや Node.js 8 に対応したので嬉しいですね!)
npm init
gcloud beta functions deploy slackChoicesBot --runtime nodejs8 --trigger-http --region asia-northeast1
デプロイ完了したら、https://asia-northeast1...
という関数の URL が出るので、これをメモしておきましょう。
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: slackChoicesBot
httpsTrigger:
url: https://asia-northeast1-xxxxxxx.cloudfunctions.net/slackChoicesBot
...
デプロイした関数は、Google Cloud Platform のコンソール からも確認できます。
Slack App の作成
Cloud Functions が準備できたので、次は Slack App を作って BOT ユーザーを作ります。
(1) Slack App と BOT User をつくる
https://api.slack.com/apps にアクセスして、Create New App ボタンから Slack App をつくり、Bot Users というメニューから BOT 用のユーザーを作ります。
(2) メンションを受け取るサーバーを指定
App 設定の Event Subscriptions をONにして、Request URL に Cloud Functions にデプロイした関数の URL を入れます。
次に、Subscribe to BOT Events のところに app_mention を追加します。
(3) 選択結果を送るサーバーを指定
App の設定で次のように、Interactivity: ON にして、Request URL に Cloud Functions にデプロイした関数の URL を入れます。
(4) Slack ワークスペースに App をインストール
App の設定の OAuth & Permissions の Scopes で、bot
という名前の scope を追加します。
そこまで完了したら、OAuth & Permissions ページにある Install App to Workspace で Slack ワークスペースにインストールしましょう。
メンションに反応して選択肢を返す
BOT に対してメンションを飛ばすと、Cloud Functions の関数に app_mention という種類のリクエストが来ます。
{
"type": "app_mention",
"user": "U061F7AUR",
"text": "<@U0LAN0Z89> is it everything a river should be?",
"ts": "1515449522.000016",
"channel": "C0LAN2Q65",
"event_ts": "1515449522000016"
}
この内容に対して、選択肢つきの返信をチャンネルに投稿する処理を書きます。チャンネルへの投稿は chat.postMessage API を普通に使います。
選択肢は Slack Attachments として記述できる ので、ドキュメントを読みながら組み立てていきました。
const request = require('request-promise-native');
async function postMessage(payload) {
await request.post('https://slack.com/api/chat.postMessage', {
headers: { 'Authorization': `Bearer ${process.env.BOT_USER_TOKEN}` },
json: payload,
});
}
const onRequest = async (req, res) => {
let payload = req.body;
if (payload.type === 'url_verification') {
return res.status(200).json({ 'challenge': payload.challenge });
}
if (payload.event && payload.event.type === 'app_mention') {
if (payload.event.text.includes('hi')) {
const slackRes = await postMessage({
text: `<@${payload.event.user}> hi!`,
channel: payload.event.channel,
attachments: [createSlackAttachment('BOT response')],
});
return res.status(200).send('OK');
}
}
...
また、チャンネルに投稿するために BOT User OAuth Access Token が必要ですが、このトークンはソースコードには含めたくないものなので、環境変数ファイルに分離 して関数をデプロイしました。
BOT_USER_TOKEN: xoxp-xxxxx...
デプロイコマンドはこんな感じです。
gcloud beta functions deploy slackChoicesBot --runtime nodejs8 --trigger-http --env-vars-file .env.yml --region asia-northeast1
選択肢を選んだ結果を受け取る
BOT が出した選択肢を選んだとき、Cloud Functions の関数に interactive_message という種類のリクエストが来ます。
リクエストの中に「どの選択肢を選んだか」などの情報がはいっているので、それに応じて関数でいろいろなことができます!
※app_mention のときと payload の形式が異なっているので注意が必要です。 app_mention はそのまま構造化された JSON で来ましたが、interactive_message のときは payload という名前のフィールドに 文字列化されたJSONが入っている 構造なので、payload を一度 JSON.parse する必要がありました。
...
const onRequest = async (req, res) => {
let payload = req.body;
...
if (typeof payload.payload === 'string') {
payload = JSON.parse(payload.payload)
}
if (payload.type === 'interactive_message') {
const action = payload.actions[0];
if (action.name === 'choices') {
const selectedOption = action.selected_options[0];
return res.status(200).send(`<@${payload.user.id}> Your select value: "${selectedOption.value}"`);
}
}
...
まとめ
全体のソースコードは GitHub にアップロードしておきました。
今回は選んだ値を Slack に出すだけの単純な BOT でしたが、これをベースに様々な BOT が開発できそうです。
最近は Cloud Functions のような関数だけをさくっと公開できるサービスが充実してて、非常に開発がやりやすいですね!
その影響もあって、プログラミングの部分よりは、Slack API の仕様の理解のほうが苦労します