重要なお知らせ
Bolt for JavaScript を Google Cloud Functions や AWS Lambda で Bolt アプリを動かす際は以下のような問題に当たる可能性があります。
シンプルな応答をするだけのアプリであればおそらく問題なく動かすことができますが、Events API のハンドリング、非同期処理の開始を含むアプリの場合はご注意ください。
2020 年 6 月更新:Bolt for JS v2 から processBeforeResponse
というオプションが導入されました。これを有効にしていれば FaaS でも期待通りに動作するようになりました。
この記事では Bolt⚡ という簡単に Slack 連携を実装するためのフレームワークを Cloud Functions for Firebase で動かす手順を紹介します。この記事時点で Bolt のバージョンは 1.2.0 です。
ちなみに 7/31-8/1 開催の Google Cloud Next ’19 in Tokyo に Slack Japan もブース出展しております。この記事を 2019/8/1 に読まれている方、私も会場におりますので、来場される方はぜひお立ち寄りください
tl;dr
- Bolt⚡ 日本語ドキュメント: https://slack.dev/bolt/ja-jp/tutorial/getting-started
- 完成形: https://github.com/seratch/bolt-on-cloud-functions-for-firebase
- こちらのスライドも参考にしてみてください: https://speakerdeck.com/roadagain/bolt-on-cloud-functions-for-firebase
Bolt⚡ とは何か
Slack と連携するアプリケーションをつくるとき、以下の二つのやりとりがあります。何か便利な Slack 連携をつくるとき、この両方を行うアプリケーションを作ることが多いでしょう。
-
- Slack に何か情報を送る(メッセージをポストする、ファイルをアップロードする、など)
-
- Slack 内で発生した情報をもらう(Slack 内で発生したイベント、コマンド・ダイアログ・ボタンなどのユーザによる操作の内容を受け取る)
JavaScript/TypeScript の場合 1) は slackapi/node-slack-sdk を使って実装することができます。2) について、この記事では Slack が提供している slackapi/bolt を紹介します。Bolt は Slack が今年 4 月末に公開したライブラリです。Bolt は 1) を簡単に行うためのユーティリティ(say
や respond
)も提供しています。
Firebase プロジェクトを始める
この記事では Cloud Functions for Firebase についての説明は割愛します。
まず firebase init
で functions のプロジェクトをつくって function の依存ライブラリに @slack/bolt
を追加してください。
Bolt は 1.2.0 時点で Node 10.13.0 以上で動作します。 package.json
の engines.node
を以下のように書き換えてください。
{
"engines": {
"node": "10"
}
}
Slack アプリの設定を行う
https://api.slack.com/apps にアクセスして Slack アプリをつくってください。動作確認したいワークスペースを指定して作成します。
次に Slash Commands のページにアクセスして /echo-from-firebase
というコマンドをつくります。Request URL はこの時点ではダミーでもよいのでとりあえず保存します(その場合は初回デプロイしたあとで更新してください)。
次に Bot Users のページにアクセスして、Bot ユーザを一つ作成してください。
最後に Install App
からのこの Slack アプリをワークスペースにインストールしてください。これによって Bot User OAuth Access Token
が発行されていますので、これを後ほど使用します。
index.js の完成形
まず、完成形は以下のようになります。/echo-from-firebase
というスラッシュコマンドを処理するコードがこれだけの行数で実装できます。以下で個々の内容を説明していきます。
'use strict'
const functions = require('firebase-functions');
const config = functions.config();
const { App, ExpressReceiver } = require('@slack/bolt');
const expressReceiver = new ExpressReceiver({
signingSecret: config.slack.signing_secret,
endpoints: '/events',
processBeforeResponse: true
});
const app = new App({
receiver: expressReceiver,
token: config.slack.bot_token,
processBeforeResponse: true
});
app.error(console.log);
app.command('/echo-from-firebase', async ({ command, ack, say }) => {
ack();
say(`You said "${command.text}"`);
});
// https://{your domain}.cloudfunctions.net/slack/events
exports.slack = functions.https.onRequest(expressReceiver.app);
firebase functions:config
config を以下のように設定して
firebase functions:config:set slack.signing_secret=522777abcabcabcabcabcabcabcabc
firebase functions:config:set slack.bot_token=xoxb-1234567890-123456789012-abcabcabcabcabcabc
それを以下のコードで呼び出します。このサンプルではリクエストの検証に必要な Signing Secret と API の利用に必要な Bot OAuth Access Token を設定します。
const functions = require('firebase-functions');
const config = functions.config();
Signing Secret は Basic Information > App Credentials にあります。 Bot OAuth Access Token は Install App に Bot User OAuth Access Token として表示されています。
Bolt の初期化
Bolt はデフォルトの実装は Express を使っています。今回はあとから functions.https.onRequest
に渡す Application
インスタンスを取得するために ExpressReceiver
を定義して App
の初期化を行なっています。
const { App, ExpressReceiver } = require('@slack/bolt');
const expressReceiver = new ExpressReceiver({
signingSecret: config.slack.signing_secret,
endpoints: '/events',
processBeforeResponse: true
});
const app = new App({
receiver: expressReceiver,
token: config.slack.bot_token,
processBeforeResponse: true
});
app.error(console.log);
その必要がないケースでは、以下のようにさらにシンプルに App
を初期化することもできます。
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET,
processBeforeResponse: true
});
メインロジック
スラッシュコマンドを処理する関数を定義する場合は、以下のように app.command
を使います。
app.command('/echo-from-firebase', async ({ command, ack, say }) => {
ack();
say(`You said "${command.text}"`);
});
app.event
や app.action
など他のリクエストを処理するためのメソッドももちろん定義されているので、ドキュメントを参照してみてください。
Firebase 互換の関数を export する
最後に先ほど定義していた expressReceicer
の app
を functions.https.onRequest
に渡して slack
という名前で export します。これによって URL は https://{your domain}.cloudfunctions.net/slack/events
のようになります。 URL の中の events
は endpoints: '/events'
の部分を変えれば違うパスにも変更できます。
// https://{your domain}.cloudfunctions.net/slack/events
exports.slack = functions.https.onRequest(expressReceiver.app);
動作確認
最後にちゃんと動いているか、実際に確認してみましょう。
Firebase にデプロイ
以下の通り、firebase-cli でデプロイします。作ったばかりのプロジェクトであれば Billing Info の更新をお忘れなく。
firebase deploy --only functions
Slack 上でテスト
設定を行なった Slack ワークスペース内の動作確認を行いたいチャンネルにつくった Bot ユーザを invite してください。 /invite @user-name
で招待するか、メンションしてください。
そして、 /echo-from-firebase hello
と入力してみてください。 You said "hello"
と応答してくれるはずです。
まとめ
簡単ですが Bolt を使った Slack 連携アプリを Cloud Functions for Firebase にデプロイする手順をご紹介しました。ぜひ試してみてください。
やってみて何かわからないことなどがあったら、以下のリンクからコミュニティに参加して、そこで質問をしてみてください!
Slack コミュニティ公式グループ community.slack.com に参加しませんか?(日本語は #lang-japanese チャンネルへどうぞ!)
https://qiita.com/girlie_mac/items/93538f9a69eb4015f951#comment-a983ea977482e78f209c
また、繰り返しとなりますが Slack Japan は 7/31 と 8/1 の Google Cloud Next ’19 in Tokyo にブース出展しております。この記事を 2019/8/1 に読まれた方でイベントに来場される方は、ぜひお立ち寄りください(私も Slack ブースにおります)