こんにちは。楽楽勤怠バックエンドチームのmako_makokです。
皆様はSlack アプリを開発されるときはどうやって開発されていますか?
Hubotでしょうか?それともHttp Clientから直で叩いていますか?
今回はSlack APIを簡単に使え、爆速でSlack アプリを開発するためのフレームワークBolt
のご紹介をさせていただきます。
Boltとは
Slack APIチーム謹製のSlack API Client + スラッシュコマンド用のレシーバを兼ね備えた、Slack アプリ開発用のフレームワークです。
現時点ではJavaScript(TypeScript), Java, PythonのSDKが配布されています。
オープンソースで開発されていおり、リポジトリはそれぞれ以下です。
JavaScript
主にTypeScriptで開発されています。
型フレンドリーにSlack APIを使用することができます。
github.com
Java
kotlin用のextensionやSpring BootやKtorなどJava, KotlinのWeb Frameworkへのextensionやサンプルなども豊富にあります。
Python
type hintフレンドリーな開発ができます。
一部独自のアプローチでSlack アプリが抱える問題を解決したりしています。
github.com
どの言語でも細かな差はありますが、基本的なインターフェースは同じなので自身の好きな言語を選択してください。
今回はbolt-js
を使用して解説していこうと思います。
スラッシュコマンドについて
Boltの説明に入る前に、スラッシュコマンドについて説明します。
スラッシュコマンドは、Slack上で/foo
のようにし、それをトリガーとして様々なアクションを行うことができます。
もし既にSlackをインストールしてあるのであれば、/
と入力してみてください。
デフォルトで登録されているいくつかのスラッシュコマンドが一覧表示されます。
続けて/remind
と入力してみると、リマインダー登録用のモーダルが表示されると思います。
スラッシュコマンドの概要
スラッシュコマンドを簡略化すると、以下のように動いています。
スラッシュコマンドを入力すると、指定したエンドポイントにSlackからHttp Requestが送られてきます。
スラッシュコマンドを登録する
スラッシュコマンドはhttps://api.slack.com/apps/{app_id}/slash-commands
にアクセスし、Create New Command
を押すと以下の画面が出てきます。
Commandに登録したいスラッシュコマンド、Request URLにSlackからのリクエストを受け取るエンドポイントを設定します。
Boltを使う
Slack APIを使うために、Boltの初期化をしていきます。
今回はbolt-js
を利用するので、npmでインストールします。
プロジェクトを作成し、npm install @slack/bolt
とするだけでインストールが完了します。
TypeScriptはお好みで入れてください。
最初にAppをインスタンス化します。
import { App } from '@slack/bolt' const app = new App({ token: process.env.SLACK_BOT_TOKEN, signingSecret: process.env.SLACK_SIGNING_SECRET, }) (async () => { // Start your app await app.start(process.env.PORT || 3000); console.log('⚡️ Bolt app is running!'); })();
tokenとsingleSecretは以下から取得することができます。
singleSecret
https://api.slack.com/apps/{app_id}
token
https://api.slack.com/apps/{app_id}
Slack API を叩いてみる
Boltの初期化は完了したので、実際にSlack APIを叩いていきます。
以下はchat.postMessageを叩いて、チームメンバーが参加したらメッセージを送信するサンプルです。
app.event('team_join', async ({ event, client }) => { try { await client.chat.postMessage({ channel: 'foo', text: `いらっしゃい、<@${event.user.id}>! 🎉`, }) } catch (error) { console.error(error) } })
第一引数にイベント名、第二引数にリスナーを設定します。
リスナーのclientは認証済みのものが渡されるので、すぐにSlack APIを叩くことができます。
また、リスナーを介さずSlack APIを叩くことも可能です。
App自体がWebClient
を持っているので、tokenを都度渡して実行します。
await app.client.chat.postMessage({ token: process.env.SLACK_BOT_TOKEN, channel: 'foo', text: `いらっしゃい、<@${event.user.id}>! 🎉`, })
さらに、BoltにはSlack APIを更に簡単に扱うためのユーティリティが用意されています。
例えば、更に簡単にchat.postMessage
を実行できるsay()
関数などがあります。
以下は「おはよう」というメッセージに反応して、「今日もいい天気!」と返すスクリプトです。
app.message('おはよう', async ({ message, say }) => { await say(`今日もいい天気!`); });
say()
関数はチャンネルが特定できるイベントであれば、使用することができます。
スラッシュコマンドを作る
Boltでは簡単にスラッシュコマンドを作ることができます。
レシーバーの作成
Slackからのリクエストを受け取ってレスポンスを返すレシーバー、以下のように設定します。
import { App, ExpressReceiver } from '@slack/bolt' export const expressReceiver = new ExpressReceiver({ signingSecret: process.env.SLACK_SIGNING_SECRET, endpoints: '/events' }) export const app = new App({ receiver: expressReceiver, token: process.env.SLACK_BOT_TOKEN })
ExpressReceiver
をApp
に渡すだけで、簡単にレシーバーの設定をすることができます。
エンドポイントは/events
と記載してありますが、実際のルーティングは/slack/events
となるので注意してください。
このエンドポイントを「スラッシュコマンドについて」で紹介した、Request URLに設定して準備完了です。
スラッシュコマンドのアクションを作成する
スラッシュコマンドを入力されたときのアクションを書いていきます。
今回は/register-word
というスラッシュコマンドが入力されると、モーダルが開き、情報を入力してsubmitすると入力された内容が送信され、それを受けとるサンプルです。
const close: PlainTextElement = { type: 'plain_text', text: 'キャンセル' } const submit: PlainTextElement = { type: 'plain_text', text: '登録' } function buildBlocks(): KnownBlock[] { const keywordInput: InputBlock = { type: 'input', block_id: 'keyword', label: { type: 'plain_text', text: '検索ワード', }, element: { type: 'plain_text_input', action_id: 'keyword_input', }, } // ... return [keywordInput] } const VIEW_ID = 'dialog_1' export const register = (app: App) => { app.command('/register-word', async ({ ack, body, context, command }) => { await ack() try { await app.client.views.open({ token: context.botToken, trigger_id: body.trigger_id, view: { type: 'modal', callback_id: VIEW_ID, title: { type: 'plain_text', text: '検索ワードの登録', }, blocks: buildBlocks(), private_metadata: command.channel_id, close, submit }, }) } catch (err) { console.error(err) } }) app.view(VIEW_ID, async ({ ack, view, context, body }) => { await ack() const values = view.state.values const keyword = values.keyword.keyword_input.value // ... }) }
まずapp.command
でスラッシュコマンドを待機します。
app.command('/register-word', async ({ ack, body, context, command }) => { }
最初にack()
関数を実行します。
この関数はSlackに対して即座にレスポンスを返すことができます。
スラッシュコマンドは3秒以内にレスポンスを返さないといけないというルールがあるので、まずはレスポンスを返します。
後続の処理は非同期で実行されます。
await ack()
スラッシュコマンドを受け取ったらviews.openを叩きます。
このAPIではBlock Kitで作成されたViewを表示することができます。
submitに登録されているオブジェクトがクリックされると実際にsubmitされます。
submitされたフォームのデータはapp.view
で受け取ることができます。
app.view(VIEW_ID, async ({ ack, view, context, body }) => { await ack() const values = view.state.values const keyword = values.keyword.keyword_input.value // ... })
views.openで設定されたcallback_id
を検知して発火します。
フォームの中身はview.state.values
の中にあります。
values以下のオブジェクト構造はviews.openで使用しているBlock Kit内で決めることができます。
const keywordInput: InputBlock = { type: 'input', block_id: 'keyword', label: { type: 'plain_text', text: '検索ワード', }, element: { type: 'plain_text_input', // action_idがvalues以下のプロパティとなる action_id: 'keyword_input', }, }
余談: Block Kit
Block Kitを利用することで、複雑なUIを表現する事ができます。Block Kitについては公式のドキュメントがわかりやすいです。
また、Block Kit Builderというツールもあり、プレビューしながらUIを構築することが可能です。
まとめ
今回はBoltについて紹介させていただきました。
今回紹介しきれなかった機能もたくさんあるので、みなさんもぜひ触ってみてSlackアプリを作ってみてください。
改めて、Boltのメリットをまとめます。
- Slack APIチームがメンテナンスしているので、信頼性が高い
- 型安全にSlack APIを扱うことができる
- Slack APIを簡単に使うための便利なユーティリティ
- スラッシュコマンド用のレシーバーを簡単に生成できる
おまけ
Bolt + Firestore + Cloud Functions
成果物として、スラッシュコマンドからワード登録モーダルを開き、毎朝バッチで勉強会情報を通知してくれるサンプルを作ってみました。
よろしければ参考にしてみてください。
参考
- Bolt入門ガイド(https://slack.dev/bolt-js/ja-jp/tutorial/getting-started)
- Slack API(https://api.slack.com/apis)
- Bolt for JavaScript を使った Slack アプリ開発で知っておくと捗る 7 つのこと(https://qiita.com/seratch/items/dcedc7476eac5f681d30)
※冒頭画像のSlackロゴは、公式サイトで配布されているものを使用しております。
エンジニア中途採用サイト
ラクスでは、エンジニア・デザイナーの中途採用を積極的に行っております!
ご興味ありましたら是非ご確認をお願いします。
https://career-recruit.rakus.co.jp/career_engineer/カジュアル面談お申込みフォーム
どの職種に応募すれば良いかわからないという方は、カジュアル面談も随時行っております。
以下フォームよりお申込みください。
rakus.hubspotpagebuilder.comラクスDevelopers登録フォーム
https://career-recruit.rakus.co.jp/career_engineer/form_rakusdev/イベント情報
会社の雰囲気を知りたい方は、毎週開催しているイベントにご参加ください!
◆TECH PLAY
techplay.jp
◆connpass
rakus.connpass.com