基礎からはじめる入門者向けSlackアプリ開発(Express, Bolt)
リモートワークも増えSlackなしでは業務が円滑に進まないという会社も増えてきています。そんなユーザの人の中から毎日使っているSlackだから何か別の用途でSlackを利用することで業務を効率化できないだろうかと考える人もいるかと思います。そんな人のためにSlackでは他のアプリと連携を行うためのAPIを公開しています。APIを一般に公開してくれているおかげでGoogleやTrello, Dropox, Boxなどのメジャーなアプリとの連携だけではく自社のアプリケーションとも連携することができます。
ここ数年で以前よりもSlackのAPI開発の敷居も下がり比較的簡単にインタラクティブなUIを持つ機能を追加することも可能です。
Slackの開発をチャレンジしてみたい人、また数年前にIncoming Webhooksで通知機能は実装したけどそれ以降は何もSlack開発をしてないという人、SaaSのサービスを使ってるけどSlack開発で自社用の同程度のサービスを作れないだろうかという人向けに本書を公開しています。
本文書では外部からSlackへの外部からのメッセージ送信からサーバを使ったユーザとのインタラクティブなアプリ開発の基礎まで一から説明を行っています。
Slackを今以上に活用できるようにぜひ本文書を参考にアプリ開発にチャレンジしてみてください。
本文書を利用してアプリ開発を行うためにはJavaScriptの知識が必要となります。node,npmもインストールしておく必要があります。本書ではSlack上でのユーザ間のメッセージ送信、Slackの通常の利用方法についての説明は一切行っておりません。
Slackのアカウント登録
Slackは無料の場合は検索できるメッセージの件数や外部アプリとの連携数、複数でのビデオ通話などいくつか制限がありますが無料の範囲で十分に業務に活用させることができます。
Slackを利用するためにはアカウント登録(ワークスペースの作成)が必要となるためSlackのサイトにアクセスして右上にある”無料で試してみる”ボタンをクリックしてください。
Slackで利用するメールアドレスの入力画面が表示されます。英語で表示されている場合は”Change region”(地域を変更)をクリックすることで日本語に変更することができます。
Asia Pacificの日本(日本語)を選択してください。
日本語が表示されるので、業務で利用する場合は仕事用のメールアドレスを入力してください。(Slack推奨)
メールアドレスを入力して”続行する”ボタンを押すとコードの入力画面が表示されます。
登録したメールに6文字のコードが送信されてくるのでそのコードを入力してください。
メールに表示されている6文字のコードを入力するとワークスペースの新規作成画面が表示されるので”ワークスペースを作成する”ボタンをクリックしてください。
ワークスペースの名前を入力してください。会社名または部署名などを入力します。
ここで入力する名前は、ワークスペースで利用するチャンネルの名前になります。後ほど変更することが可能です。
Slackを利用する場合は会社または部署のメンバーとメッセージをやりとりすることになるのでメッセージをやりとりする予定の他のメンバーのメールアドレスを入力してください。この手順はスキップすることが可能なのでスキップする場合は”この手順をスキップする”をクリックしてください。
スキップする場合は下の画面が表示されるので”ステップをスキップ”をクリックしてください。
以上でSlackの新規アカウント(ワークスペース)の作成は完了です。2番目のステップで入力した名前がチャンネルの下に作成されていることが確認できます。
ユーザのメールアドレスのみでパスワードを設定しませんでしたがパスワードなしでもサインインの画面でメールアドレスを入力すると6桁の文字列が登録したメールアドレス向けに送信されてくるのでサインインすることができます。パスワードも設定することは可能です。
Slackのアプリケーションを作成する
Slackで最も行われている開発の一つが外部のアプリケーションからSlackに向けて行う通知(メッセージ送信)です。外部アプリケーションから一方的に通知を行うのみなのでSlack側から外部アプリケーションにメッセージを送ることはありませんSlackの開発を行う上での基礎となるのでまずはメッセージ送信機能を作成してみましょう。
Slackではメッセージ送信機能を作成する場合でも必ずslack apiでアプリを作成する必要があります。作成というよりもアプリの登録という表現の方が正しいかもしれません。
slack apiでアプリケーションを作成し外部からメッセージを送信してslackのユーザが受信するまでに行う処理の流れは下記の通りです。外部からメッセージを送信し、送信したメッセージをSlack上のユーザが受信するだけのアプリであれば初めての人でも簡単に行うことができます。
- slack apiでのSlack Appの作成
- Permissions(権限)の設定
- 作成したアプリのワークスペースへのインストール
- Tokenの取得(自動で作成されます)
- curlコマンドによりメッセージの送信
Slack appの作成
Slackでアプリケーションを開発するためにはSlackにアプリケーションの登録を行う必要があります。アプリケーションを作成するためにslack apiの画面にアクセスします。slack apiが開いたら”Create a custom app”ボタンをクリックします。
アプリケーション名の入力とワークスペースの選択画面が表示されるので任意のアプリケーション名と先ほど作成したワークスペースを選択してください。ここではFirst Appという名前をつけています。入力が完了したら”Create App”ボタンをクリックしてください。
作成が完了すると作成したアプリケーションに関する画面が表示されます。
Permissions(権限)の設定
Slackのアプリを動作させるためにはアプリが行える処理の範囲を決めるためScopeを設定する必要があります。Scopeを設定しなければ作成したアプリは何も行うことができません。先ほどの画面の”Permissions”を選択してください。
Permissionsをクリックすると”OAuth & Permissions”の画面が表示されます。スクロールして”Scopes”を表示してください。
ScopesではBot TokenかUser TokenのScopesを選択することができます。User Tokenを選択するとアプリを作成したユーザとして与えられた権限内で処理を行うことができます。Botを選択するとユーザではなくBotユーザとして与えられた権限内で処理を行うことができます。本文書ではBotとして処理を実行させるのでBot Token Scopesのみ利用します。
Botに対してchat:writeというScopeを与えて動作確認を行います。char:writeのScopeではチャンネルやユーザに対して外部からメッセージを送信するメソッド(chat.postMessage)をBotが利用することができます。
Scopeを選択すると選択したScopeが表示されます。Scopeは複数選択することも可能で削除したい場合はゴミ箱のアイコンをクリックしてください。
アプリのワークスペースへのインストール
作成したアプリをワークスペースにインストールします。インストールしなければアプリを利用することはできません。インストールと聞くとなにか大袈裟なものに聞こえてきますが、ワークスペースで作成したアプリを有効化するものだと思ってください。
サイドバーにある”Basic Information”をクリックします。BotにScopeを設定したことで”Add features and functionality”にチェックが入っていることがわかります。
Install your appから”Install to Workspace”をクリックします。
作成したアプリケーションがワークスペースにアクセスする権限を許可するかどうか確認画面が表示されるので”許可する”ボタンをクリックしてください。
アプリケーションへのインストールが完了するとInstall your appにチェックが入ります。
Slackへのアプリのインストールが完了するとSlackの画面に追加したアプリの情報が表示されていることが確認できます。
Tokenの取得、ユーザへのメッセージの送信
アプリのワークスペースへのインストールが完了したらcurlコマンドを利用してメッセージを送信してみましょう。メッセージの送信にはchat.postMessageメソッドを利用します。
botを利用する場合はscopeでchat:writeを設定しておく必要があります。(本書では設定済)。chat.postMessageメソッドについては詳細はhttps://api.slack.com/methods/chat.postMessageから確認を行ってください。
curlコマンドでメッセージを送信する際は以下の通りとなります。channelとありますがここでは@ユーザ名でユーザに対してメッセージを送信しています。
% curl -X POST -H 'Authorization: Bearer xoxb-XXX..XX' -H 'Content-type: application/json;charset=UTF-8' --data '{"channel":"@username","text":"Hello"}' https://slack.com/api/chat.postMessage
Bearerの後ろに入っている値はTokenで各自の環境で異なり、OAuth & PermissionsのBot User OAuth Access Tokenから取得します。Tokenは値がわかると他の人も利用することができるので公開しないように注意してください。
curlコマンドが利用できない環境の場合は動作確認用のtestページTesterをslack側で用意しているのでそこからメッセージを送信することができます。tokenなど必要な項目を入力して実行してみださい。
https://api.slack.com/methods/chat.postMessage/test
動作確認のため数回メッセージを送信していますがchannelで指定したユーザのSlack画面では送信したメッセージが表示されています。
chat.postMessageメソッドにより外部からSlackにメッセージが送信できることが確認できました。
Incoming Webhooksによる送信
postMessageメソッドを利用してcurlコマンドで外部からSlackのユーザにメッセージを送信することができました。外部からのメッセージ送信にはIncoming Webhooksという方法で行うことも可能です。
Basic Informationの画面からAdd features and functionalityからIncoming Webhooksを選択します。
Incoming WebhooksはデフォルトではOffになっているのでOnに変更します。
ONにするとWebhook URLs for Your Workspaceが表示され”Add New Webhook to Workspace”ボタンが表示されます。ボタンをクリックします。
First AppでIncoming WebhooksをONにしたので権限の確認画面が表示されます。Incoming Webhooksではどのチャンネル、ユーザ、Botにメッセージを送信するか選択することができます。ここではアカウント作成時に追加したチャンネルの”slack新規導入プロジェクト”を選択して”許可する”ボタンをクリックします。
Webhookを利用してメッセージを送信する場合はトークンではなく表示されているWebhook URLに対してPOSTリクエストを送信することでメッセージを送信することができます。curlコマンドのサンプルコマンドも表示されているのでコピーをしてコマンドラインで実行してください。何も変更することなくチャンネルにメッセージを送信できることが確認できます。
postMessageメソッドとWebhookはどちらもcurlコマンドで外部からメッセージを送信することができましたがここまでの動作確認だけでも以下の違いが確認できました。
- postMessageメソッドはアプリのScopeを設定し、メッセージを送信する際にTokenが必要となる。
- postMessageメソッドは送信時に送信するチャンネルを指定することができるがWebhookの場合はワークスペースに追加する際にチャンネルを指定する必要がある。
- Webhookの場合はTokenを利用せずSlackによって生成される一意のWebhook URLに対してメッセージを送信する必要がある。
決められたチャンネルにメッセージを送信したいのであればWebhookの方が簡単に設定を行うことができます。
Slackでの開発
Slackで開発を行う際に参考になるドキュメントはhttps://slack.dev/で公開されています。こちらに公開されているドキュメントを元に開発を行っていきます。
JavaScript、Python, Javaの3つの言語のSDKがSlackから提供されているのでいずれかを利用することで開発を効率的に行うことができます。本文書ではJavaScriptで開発を進めています。
WebhookやpostMessageで動作確認を行いましたが2つの処理は外部からSlackに対してHTTPリクエストのPOSTメソッドでメッセージを送信するという処理でした。ここまでの処理とは逆のSlackから外部に対してHTTPリクエストを送信することができます。HTTPリクエストを受け取るためにはサーバが必要となります。開発の段階ではサーバは決まっていない場合はローカルで開発を行う必要があります。ローカルで開発を行うためにSlackの公式ドキュメントで紹介されているngrokを利用します。
ngrokをローカルのPCで実行するとngrokから一意のURLから提供されます。ngrokのURLとローカルPCのポートが紐づけられngrokインターネット上からそのURLにアクセスを行うとローカルで起動したサーバに直接アクセスを行うことができます。ngrokは仲介(proxy)の役割をします。ngrokのURLはインターネット上に公開されるURLなのでインタネットに繋がっていれば誰でもアクセスすることができます。そのURLをSlackに教えることでSlackはそのURLに向けてHTTPリクエストを送信し、ngrokを経由してローカルのサーバがリクエストを処理することができます。
ngrokのアカウントの作成と設定
ngrokを利用するためにはアカウントの作成が必要となります。アカウントを作成するためngrokのサイトにアクセスします。ngrokはフリープランが準備されているので無料で利用することができます。サインアップ(アカウント作成)するために”Get started for free”ボタンをクリックしてください。
Github、Googleアカウントまたはメールアドレスでアカウントの作成を行うことができます。
アカウントの作成が完了するとアプリケーション(バイナリの実行ファイル)のダウンロードを行う必要があります。アカウント作成後にはダッシュボードにmacOS用のダウンロードリンクが表示されます。本文書ではmacOSを利用しているためです。
アプリケーションのダウンロードを行ってください。アプリケーションはzipコマンドに入っているので解凍する必要があります。解凍するとバイナリの実行ファイルであるngrokファイルが作成されます。
任意の場所にフォルダを作成して解凍したngrokファイルを移動していください。ここではDesktopにslack_devフォルダを作成してngrokファイルを保存しています。
ダッシュボードの説明に記載されている通りngrokコマンドを実行してngrokのアカウントとの接続を行います。各自異なるauthtokenが表示されているのでページからコピー&ペーストしてngrokを保存した場所からコマンドを実行してください。
実行すると”ngrokは、開発元を検証できないため開けません”のメッセージが表示された場合は”キャンセル”ボタンをクリックしてください。
キャンセルボタンをクリック後にシステム環境設定→セキュリティとプライバシーの一般タブを開いて”このまま許可”ボタンをクリックしてください。
再度実行すると”ngrok”の開発元を検証できません。開いてよろしいですか?と表示されるので”開く”ボタンをクリックしてください。
実行するとユーザのホームディレクトリ直下に隠しフォルダ.ngrokにngrok.ymlが作成されます。
Authtoken saved to configuration file: /Users/ユーザ名/.ngrok2/ngrok.yml
作成されたファイルには指定したauthtokenが保存されています。
これから動作確認のローカルのポート3000を利用するのでngrokへのアクセスがローカルのポート3000に転送される(forwarding)ようにngrokを起動します。
ngrok by @inconshreveable (Ctrl+C to quit)
Session Status online
Account slack_dev (Plan: Free)
Version 2.3.35
Region United States (us)
Web Interface http://127.0.0.1:4040
Forwarding http://514aXXXXXXX.ngrok.io -> http://localhost:3000
Forwarding https://514aXXXXXXX.ngrok.io -> http://localhost:3000
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
http://514aXXXXXXX.ngrok.ioへのアクセスがhttp://localhost:3000に転送される設定になっていることが確認できます。
ngrokのURLにブラウザからアクセスするとローカルのポート3000で起動しているサーバは何もないためエラーが表示されます。
Expressサーバによる動作確認
Slackの開発の理解を深めるためにまずはExpressサーバを利用します。Expressサーバで動作確認後、Slackから提供されているBoltというJavaScriptフレームワークを利用します。
Expressサーバを設定してローカルのポート3000で起動させます。
npm init -yコマンドをslack_envフォルダで実行します。slack_envフォルダにはpackage.jsonファイルが作成されます。
% npm init -y
Expressのパッケージをインストールします。
% npm install express
index.jsファイルを作成しポート3000でExpressサーバは起動し、ルートにGETリクエストが来た場合はHello World!を返します。
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(port, () => console.log(`listening on port ${port}!`));
index.jsを作成したらnodeコマンドでExpressサーバを起動します。
% node index.js
listening on port 3000!
再度ブラウザからhttp://514aXXXXXXX.ngrok.ioにアクセスを行います。Hello World!が表示されればngrokからポート3000に転送、ブラウザへのExpressサーバからのレスポンスが正常に返されていることが確認できます。
Slackからのイベントの取得
Expressサーバの動作確認が完了したのでSlackからサーバに向けて送信されるHTTPリクエストの処理方法を確認していきます。
Slackからのイベントを取得できるように設定を行っていきます。これまで外部からSlackに向けての動作を確認できていましたがここでようやくSlackから外部向けに送信されるメッセージを取得できるかの確認を行います。
イベントをサーバ側でリスニングできるように@slack/events-apiパッケージをインストールします。リスニングとはSlackから送信されてくるHTTPリクエストを待ち受けておくことを言います。
% npm install @slack/events-api
@slack/events-apiパッケージに入っている検証サーバをコマンドを利用して起動することで動作確認を行います。ポート3000(ngrokでフォーワードしているポート)でイベントをリスニングしますが実行するためにはsigning_secretが必要となります。このsigninig_secretを利用することでSlackからメッセージが送信されてきていることを検証します。
./node_modules/.bin/slack-verify --secret <signing_secret> [--path=/slack/events] [--port=3000]
signing_secretはSlack APIのBasic InformationのApp Credentialsから取得することができます。
Siginig Secretを設定して検証サーバを起動します。signing_secretにはslack apiのApp Credentialsから取得した値を設定してください。環境により異なります。
% ./node_modules/.bin/slack-verify --secret siginig_secret
The verification server is now listening at the URL: http://:::3000/slack/events
検証サーバの起動が完了したら、slack api側でイベントの設定を行います。イベントの設定はslack apiのダッシュボードから行います。デフォルトではEventsはOffになっているのでOnに変更する必要があります。
OnにするとRequest URLの入力欄が表示されるのでngrokのURLを入力します。URLには検証サーバ時にデフォルトで設定されているpathの/slack/eventsも設定してください。pathオプションを起動時に変更した場合は変更した値を設定してください。
URLを入力するとchallengeパラメータの送信が行われて、入力したURLからレスポンスをもらう必要がありまs。正常に動作しない場合は下記のように表示されます。
正常に動作した場合はverifiedが表示されます。verifiedが表示されればサーバ側でslackからのHTTPリクエストを受け取ることができるのでイベントの取得の動作確認に進めます。
Expressサーバでイベントを取得
ExpressサーバにおけるEvents APIの設定方法についてはslack.devのEvents APIに記述されているのでその設定を参考にしています。
const { createServer } = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const { createEventAdapter } = require('@slack/events-api');
const slackSigningSecret = process.env.SLACK_SIGNING_SECRET;
const port = process.env.PORT || 3000;
const slackEvents = createEventAdapter(slackSigningSecret);
const app = express();
app.use('/slack/events', slackEvents.requestListener());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.get('/', (req, res) => res.send('Hello World!'));
slackEvents.on('message', (event) => {
console.log(`Received a message event: user ${event.user} in channel ${event.channel} says ${event.text}`);
});
const server = createServer(app);
server.listen(port, () => console.log(`listening on port ${port}!`));
slackEvents.onメソッドでmessageイベントを取得しています。messageイベントを取得するためにはBotがmessageイベントを取得できるようにイベントの設定をslack apiのダッシュボード上で行う必要があります。Event SubscriptitonsのページのSubscribe to bot eventsでmessage.imイベントを追加してください。message.imイベントを設定することでFirst Appアプリにユーザからメッセージを送信するとSlackからメッセージがExpressサーバ側に送信されます。
message.imを追加するとアプリに対する権限を設定し直す必要がありScopeの追加も必要となります。message.imで必要となるScopeはim:historyのためScopeの設定画面に移動します。
Scopeの設定はOath & Permissionsのページから行うことができます。message.imを”Subscribe to bot events”の設定で追加すると自動でScopeにim:historyが追加されます。追加したらアプリのワークスペースへの再インストールが必要となります。
ワークスペースへのアプリの再インストールはBasic Informationのページのみで行えるわけではありませんが今回はBasic Informationの”Reinstall to Workspace”ボタンをクリックします。
再インストールする際は必ず許可の確認が表示されるので”許可する”ボタンをクリックしてください。
Slack上でのイベントの設定は完了です。本当にイベントが発生し、Expressサーバ側でmessageイベントを取得できるのか確認するためにSlackの画面上からFirst App(アプリ)に対して直接メッセージを送信します。”ベントをExpressサーバで受け取れるかの確認です。”を送信しています。
index.jsファイルではmessageイベントを取得するとコンソールにメッセージを表示できるように設定しているのでExpressサーバを起動したターミナルにメッセージが表示されてればSlackからイベントメッセージがngrok経由でExpressサーバに送信され、正常に受信できていることが確認できます。
% SLACK_SIGNING_SECRET=XXXXXXX node index.js
listening on port 3000!
Received a message event: user U01NX4Q7P7F in channel D01NKM0M78X says イベントをExpressサーバで受け取れるかの確認です。
もし受信できない場合はngrokのInspectを利用してSlack側からHTTPリクエストが来ているのか確認することもできます。
イベントの設定の間違いやイベントを発生させるための処理に誤りがある場合はリクエストには何も表示されません。(HTTPリクエストがSlackから送信されてこないため)
イベントがSlackから送信し、ngrokが受信している場合は/slack/eventsにPOSTリクエストが来ていることがわかります。リクエストの中身の詳細もページ右側の部分で確認することができます。
Expressサーバからメッセージの送信
SlackからExpressサーバに対してメッセージの送信が確認できたので今後はExpressサーバからSlackに対してメッセージを送信します。
本文書ですでに確認済のchat.postMessageでメッセージを送信するために@slack/web-apiパッケージのインストールを行う必要があります。今回はcurlではなくExpressサーバのコード内でchat.postMessageメソッドを実行します。
% npm install @slack/web-api
index.jsファイル内ではBotとしてメッセージを送信することになるのでBot User OAuth Access Tokenが必要となります。コードではBot User OAuth Access TokenをSLACK_BOT_TOKENに設定しています。
インストールした@slack/events-apiパッケージからWebClientクラスをimportしてSLACK_BOT_TOKENを引数としてインスタンス化しています。メッセージの送信はweb.chat.postMessageメソッドを使って送信するメッセージをtext、送信したいチャンネルに’slack新規導入プロジェクト’に設定しています。
const { createServer } = require('http');
const express = require('express');
const bodyParser = require('body-parser');
const { createEventAdapter } = require('@slack/events-api');
const { WebClient } = require('@slack/web-api'); //追加
const slackSigningSecret = process.env.SLACK_SIGNING_SECRET;
const token = process.env.SLACK_BOT_TOKEN; //追加
const port = process.env.PORT || 3000;
const slackEvents = createEventAdapter(slackSigningSecret);
const web = new WebClient(token); //追加
const app = express();
app.use('/slack/events', slackEvents.requestListener());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.get('/', (req, res) => res.send('Hello World!'));
slackEvents.on('message', async (event) => {
await web.chat.postMessage({
text: `受け取ったメッセージはこちらです。"${event.text}"`,
channel: 'slack新規導入プロジェクト',
});
});
const server = createServer(app);
server.listen(port, () => console.log(`listening on port ${port}!`));
Bot(First App)を”slack新規導入プロジェクト”に招待していない場合は”slack新規導入プロジェクト”のメッセージ一覧でFirst Appに対して”@First App test”でメッセージを送信してくささい。紹介されていない場合はFirst Appを招待するかどうか聞かれるので”招待する”をクリックしてください。
Slackの画面上でFirst Appに対してメッセージを送信するとチャンネルslack新規導入プロジェクトに新規のメッセージがFirst Appアプリから送られてくれば正常に動作しています。
First Appにメッセージを送信するとmessageイベントが発行されExpressサーバでmessageイベントを検知します。messageイベントを検知後にExpressサーバからpostMessageメソッドでチャンネル”slack新規導入プロジェクト”対してメッセージを送信しています。
何か設定の問題等でエラーが発生した場合に原因を特定するためにtry{}catch{}をExpressサーバのindex.jsファイルに追加しておきます。
slackEvents.on('message', async (event) => {
try{
await web.chat.postMessage({
text: `受け取ったメッセージはこちらです。"${event.text}"`,
channel: 'slack新規導入プロジェクト',
});
} catch(error){
console.log(error.data)
}
});
チャンネルにアプリを招待していない場合には下記のようなエラーメッセージ(not_in_channel)がExpressサーバを起動したターミナルに表示されます。
{
ok: false,
error: 'not_in_channel',
response_metadata: {
scopes: [ 'chat:write', 'incoming-webhook', 'im:history' ],
acceptedScopes: [ 'chat:write' ]
}
}
ExpressサーバからBoltへ
Boltは、Slackアプリをより直感的に効率的に開発することを目的に公開されているSlackの公式のJavaScriptフレームワークです。ここまでの動作確認ではExpressサーバを利用してきましたがBoltを利用してアプリの開発を行っていきます。これまでに記述したコードをBoltを使って作成します。
Boltのインストールと起動
任意の場所にプロジェクト用のフォルダを作成します。ここではslack_bolt_devという名前にしています。
% mkdir slack_bolt_dev
% cd slack_bolt_dev
% npm init -y
npm init -yを実行するとpackage.jsonファイルが作成されます。次にnpmコマンドで@slack/boltパッケージのインストールを行います。
% npm install @slack/bolt
index.jsファイルを作成し、Boltを起動するためのコードを記述します。このコードがベースとなります。
const { App } = require('@slack/bolt');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
(async () => {
await app.start(process.env.PORT || 3000);
})();
Slackからイベントを受け取ってメッセージをSlackに送信するコードをBoltで記述すると下記のようになります。コードは似ていますがExpressサーバの時のコードよりもすっきりしていることがわかるかと思います。
const { App } = require('@slack/bolt');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
app.event('message',async({event,client}) => {
try {
const result = await client.chat.postMessage({
text: `受け取ったメッセージはこちらです。"${event.text}"`,
channel: 'slack新規導入プロジェクト',
});
}
catch (error) {
console.error(error);
}
});
(async () => {
await app.start(process.env.PORT || 3000);
})();
sayメソッド
メッセージを送信する際にchat.postMessageを利用していましたがイベントが発生した場所にメッセージを送信したい場合はsayメソッドを利用することができます。postMessageで指定したchannelなどを設定する必要がなくシンプルなコードで実行することができます。
app.event('message',async({event,say}) => {
await say('sayメソッドで送信')
});
イベントが発生したその場所にメッセージを送信することができるのでFirst Appにメッセージを送信するとsayメソッドの内容はFirst Appのメッセージ一覧に表示されます。もしアプリにmessage.channelsイベント(チャンネルにメッセージが書き込まれた場合に発生するイベント)を設定している場合はメッセージを書き込んだチャンネルにsayメソッドの中身のメッセージが表示されます。
Slashコマンドの設定
ユーザがSlack内で明示的に行う処理に対して何か別の処理を行えるようにSlashコマンドの動作確認を行います。
SlackではデフォルトでもSlashコマンドが登録されており、例えばチャンネルのメッセージフィールドに/whoと入力するとチャンネルに参加しているメンバーが表示されます。そのほかに/searchと入力すると検索ボックスが表示されるなど便利な機能があります。
既存のものだけではなくオリジナルのSlashコマンドをアプリ内で作成してSlackで実行させることができます。slack apiのダッシュボードからSlash Commandsのページを開きます。Slashコマンドの追加を行うので”Create New Command”ボタンをクリックしてください。
Slashコマンドの入力フォームが表示されるので入力項目を埋めていきます。
実際にSlackのメッセージフィールドで入力するコマンド名をCommandに入力し、Reqeust URLはngrokのURLを設定します。イベントで設定したものと同じURLです。Short Descriptionにはコマンドの説明を入力します。入力後は入力欄の下にある”Save”ボタンをクリックしてください。
新規のSlashコマンドを追加するとSlackへのアプリの再インストールが必要となるので再インストールを実行してください。
再インストール完了後、ユーザのメッセージフォームで/kitayoと入力すると入力したShort Descriptionとコマンド名が下記のように表示されます。
追加したSlashコマンドを実行することができますがBolt側で何も処理を行っていないためエラーとなります。
ngrokを実行しているターミナルにもエラーが表示されます。
[ERROR] An incoming event was not acknowledged within 3 seconds. Ensure that the ack() argument is called in a listener.
上記のエラーからSlackでは3秒以内にSlackに対して応答しなければならないことがわかります。HTTPリクエストを受け取ったことをslackに伝えるためイベント処理の内部でackメソッド(acknowledgeの略)を実行する必要があります。ackメソッドを実行することでサーバ側でSlackのHTTPリクエストを受け取ったことをSlackに伝えることができます。
commandメソッドでSlackから送信されてくるslashコマンドのイベントを受け取ることができます。下記ではack()でイベントを受け取ったことをSlackに伝え、sayでメッセージを送信しています。
/kitayoを実行するとサーバから戻されたメッセージが表示されます。
respondメソッド
メッセージを送信する方法には先ほど動作確認を行ったsayメソッドのほかにrespondメソッドがあります。sayメソッドではBotがいないチャンネルや自分のメッセージフィールドで/kitayoを実行するとchannel_not_foundエラーが発生しコマンドを実行することができません。しかし、respondメソッドを利用すると下記の図のように自分のメッセージフィールドでSlachコマンドを実行することが可能となります。
app.command('/kitayo', async({ack,respond}) =< {
await ack();
await respond('おはようございます。今日も一日がんばりましょう!');
});
ユーザへインタラクティブコンポーネントの送信
ここまではサーバからSlackに送信したメッセージはすべてテキストでした。テキストではなくリッチなUIを表現できるインタラクティブコンポーネントを利用することでボタンやセレクトボックス、ラジオボタンなどユーザがインタラクティブに操作できる要素をSlackの画面上に表示させることができます。インタラクティブコンポーネントはBlock Kitと呼ばれるSlack独自のUIフレークワークを利用して行います。Block KitはJSONで記述することができSlackからBlock Kit Builderが提供されているのでBlock Kitを作成することは難しいものではありません。
Block Kit Builder
Block Kitを作成するBlock Kit Builderのページにアクセスすると下記のように大きく3つのパートにわかれてます。右側にはJSONでコードが記述されています。右側のJSONのコードを利用することで真ん中の画面に表示されているUIをSlack上に表示することができます。左側のメニューにはSlack上で表示させたいBlockの要素一覧が表示されており、例えばボタンを表示させたい場合はButtonsをクリックすると右側にボタンに対応するJSONコードが追加され真ん中にはJSONコードに対応した画面上でのボタンが表示されます。
右側のJSONはブラウザ上で更新すると真ん中のパートに即反映されるのでBlock Kit Builderを元にして表示させたいBlock Kitを簡単に作成することができます。
インタラクティブなメッセージを表示
実際にBlock Kitを利用してインタラクティブなコンポーネントをSlack上に表示させてみましょう。
Block Kit Builderのページを開くとデフォルトでは画面に例が表示されてますが、一度削除するために右上にある”Clear Blocks”をクリックしてください。
右側にはblocksのみ表示された状態です。
ラジオボタンを利用したいので左側のメニューの”radio buttons”をクリックしてください。右側に表示されているJSONを元に作成するので右上にある”Copy Payload”をクリックしてください。これでJSONデータがコピーできます。
コピーしたデータをコードをindex.jsファイルに貼り付けてtextの中身、選択肢の言葉も変更します。/kitayoコマンドを実行するとラジオボタンで午前出社、午後出社の2つの選択肢が表示させるように設定しています。
const blocks = [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "午前出社ですか?午後出社ですか?"
},
"accessory": {
"type": "radio_buttons",
"options": [
{
"text": {
"type": "plain_text",
"text": "午前出社",
},
"value": "morning"
},
{
"text": {
"type": "plain_text",
"text": "午後出社",
},
"value": "evening"
},
],
"action_id": "radio_buttons-action"
}
},
];
このblocksをSlashコマンド実行時にSlackの画面上に表示させるようにrespondコマンドを利用して下記のように記述します。
app.command('/kitayo', async({ack,respond}) => {
await ack();
await respond({
response_type:'in_channel',
blocks:blocks,
})
});
実際にSlack画面でkitayoコマンドを実行してみましょう。実行するとBlock Kit Builderで表示されていたようなラジオボタンがSlack画面上に表示されます。
インタラクティブなコンポーネントなのでユーザがラジオボタンを選択することができます。午前出社のボタンを選択すると右側に注意のアイコンが表示されます。
エラーの内容ではアプリのページでインタラクティビティの設定が行われていないということなので設定を行います。
slack apiのダッシュボードの左側のメニューからInteractivity & Shortcutsをクリックします。InteractivityがOffになっていることが確認できます。
OffからOnに設定を行うとRequest URLを入力する画面が表示されるのでこれまでイベント、Slashコマンドで設定したURLを入力してください。
Request URLを入力後は下部にある”Save”ボタンをクリックして設定を保存してください。
これでInteractivityの設定は完了です。再度画面上でkitayoコマンドを実行してみましょう。今回も前回と同様にエラーが発生します。アイコンをクリックするとエラーメッセージが変わっていることがわかります。
今回はタイムアウトエラーになっています。
エラーの原因は表示されているラジオボタンに対応する処理が記述されていないためです。
index.jsファイルを開いて対応する処理を記述します。イベントの時はapp.event, コマンドの時はapp.commandメソッドの中で処理を記述してきました。今回の場合はapp.actionメソッドを使うことでサーバ側で処理を行うことができます。
actionの引数には先ほど説明をしていませんでしたが、index.jsファイルのblocksのaction_idに指定したradio_buttons-actionを利用します。一意のidなので複数のblockがある場合もこのidで識別することができます。
radio_buttons-actionをSlackから受け取ったらrespondメソッドでメッセージを返します。
app.action('radio_buttons-action',async({ack,respond}) => {
await ack();
await respond('サーバ側でacitonを受け取りました。')
});
再度kitayoコマンドをslackの画面で実行してください。ラジオボタンが表示された後どちらを選んでも同じメッセージが表示されます。
ユーザが行ったボタンの選択操作に対してサーバからSlackに向けてメッセージを送信できることが確認できました。最後に選択した内容によって返信するメッセージを変更してみましょう。
ボタンを選択した時に送信される値はBlock Kitのvalueの値です。午前出社を選択した場合にはmorning, 午後出社を選択した場合にはeveningとしています。
valueの値はSlackから送られてくるaction.selected_option.valueに入っているのでapp.actionの中でその値を取り出して分岐し選択したボタンによって返信する内容を変えています。
app.action('radio_buttons-action',async({ack, respond, action}) => {
await ack();
if(action.selected_option.value === 'morninig'){
await respond('おはようございます。今日も一日がんばりましょう!')
}else{
await respond('こんにちは。残り半日がんばりましょう!')
}
});
選択したボタンによってSlack上で表示される内容が変わることを確認してください。
/kitayoコマンドを実行すると選択肢が表示されます。
午後出社をクリックするとサーバから送られてくるメッセージが表示されます。
Slackへのメッセージ送信だけではなくSlackとサーバ間でのデータのやりとり、ユーザとのインタラクティブな処理も行えるようになりました。
次回は基礎編を踏まえてより実践的なアプリ開発の方法を説明する予定です。