この記事は個人ブログと同じ内容です
Boltを利用してWebアプリと連携し、Slackワークスペースに所属するユーザーに応じて通知を出し分けるAPIを作ってみたので知見として書きます。
当記事で書くこと
- Slack Appの設定
- Bolt + serverless によるSlackBotのAPI実装
- emailからユーザーとのDMチャンネルを検索
- 取得したDMチャンネルIDへのメッセージ送信
- lambdaへのデプロイ
当記事で書かないこと
- Boltを利用したOAuth周りの認証設定
- 複数ワークスペースでSlackAppを利用するため
- 今後別記事にて投稿予定
手順
【SlackApp側の設定】
Slack App 作成 ←のリンクから Slack App を作成する
App Home タブにてアプリの DM に表示するタブを設定
- "App Display Name" の Edit ボタンから、好きな display name を設定して保存する
- Messages Tab
- ここのチェックを
true
にすると Messages Tab でユーザーがメッセージを送信できるようになるAllow users to send Slash commands and messages from the messages tab
- ここのチェックを
OAuth & Permissions タブにて
- Slack API の利用に必要な以下の権限を設定する
"channels:read", "chat:write:bot", "groups:read", "im:read", "mpim:read", "users:read", "users:read.email"
以下のAPIのWorks with
に必要なscopeが書いてあります
- Install to WorkSpace する
【Slack App開発】
サンプルコードは以下のリポジトリで公開しています
まずはサーバーレスアプリケーションを開発、デプロイするためのツールをインストールします
こちらの記事で紹介されている事前準備を行ってください
Lambdaの作成
下記コマンドを実行してNode.js用の作業ディレクトリとLambdaの定義ファイル作成します。
$ serverless create --template aws-nodejs --path myService
以下を実行して初期設定を行います
$ yarn init
myService ├── .npmignore ├── handler.js ├── package.json └── serverless.yml
以下のコマンドで必要なパッケージをインストールします
$ yarn add @slack/bolt @vendia/serverless-express multiparty $ yarn add -D serverless serverless-offline
package.jsonに以下のscriptを追記します
これでyarn dev
することでlocalでデバックできるようになりました
package.json
{ ... "scripts": { "dev": "sls offline", "deploy": "npx serverless deploy" }, }
Serverlessの設定ファイルを以下の内容に変更します
serverless.yml
service: serverless-bolt-js frameworkVersion: "2" provider: name: aws runtime: nodejs12.x region: ap-northeast-1 environment: SLACK_SIGNING_SECRET: ${env:SLACK_SIGNING_SECRET} SLACK_BOT_TOKEN: ${env:SLACK_BOT_TOKEN} functions: slack: handler: app.handler events: - http: method: ANY path: /{any+} useDotenv: true plugins: - serverless-offline package: patterns: - '!.git/**' - '!README.md'
あわせて環境変数を追加します
.env
SLACK_SIGNING_SECRET="xxx" SLACK_BOT_TOKEN="xoxb-xxx"
準備ができたら処理を書いていきます
handler.js
const { App, ExpressReceiver } = require("@slack/bolt"); const serverlessExpress = require("@vendia/serverless-express"); const multiparty = require("multiparty"); const accessToken = process.env["SLACK_BOT_TOKEN"]; const expressReceiver = new ExpressReceiver({ signingSecret: process.env["SLACK_SIGNING_SECRET"], processBeforeResponse: true, }); const app = new App({ token: accessToken, receiver: expressReceiver, }); // /slack/events/massegesへのpostリクエストのエンドポイント作成 app.receiver.router.post("/slack/events/masseges", async (req, res) => { // req から fields を抽出する const data = await new Promise((resolve, reject) => { const form = new multiparty.Form(); form.parse(req, (err, fields, files) => { resolve(fields); }); }); // validation if (!data.email) { res.status(400).send("error: no_email"); return; } if (!data.text) { res.status(400).send("error: no_text"); return; } const userEmailList = data.email.find((_, i) => i === 0).split(","); const massege = data.text.find((_, i) => i === 0); let userIds = []; for (const email of userEmailList) { try { // reqパラメーターのemilがワークスペースに存在するか確認 const user = await app.client.users.lookupByEmail({ token: accessToken, email: email, }); if (user) { userIds = [...userIds, user.user.id]; } } catch (error) { res.status(400).send(`error: user is Not Found. ${email}`); return; } } // DMチャンネル一覧を取得 const conversationsList = await app.client.conversations.list({ token: accessToken, types: "im", }); const channels = conversationsList.channels; if (!!userIds.length) { // メールアドレスから取得したユーザーの DM チャンネルのみにフィルター channels .filter((x) => { return userIds.some((y) => { return y === x.user; }); }) .forEach((x) => { // メッセージ送信 app.client.chat.postMessage({ token: accessToken, channel: x.id, blocks: massege, }); }); } res.status(200).send("success!!"); }); // Handle the Lambda function event module.exports.handler = serverlessExpress({ app: expressReceiver.app, });
デプロイ
以下コマンドでlambdaへデプロイします
yarn deploy
これで完成です!
試してみる
APIエンドポイントに対してcurlでリクエストを送ってみる (email が一致したユーザーは Slack の DM にメッセージが送信される)
通知メッセージを作成する
paramater
- email : カンマ( , )区切りで通知を送信したいユーザーのメールアドレスを渡す
- text : メッセージの block を作成しパラメーターに渡す
- Block Kit Builder にて作成する
$ curl --location --request POST 'https://xxxxxxxxxx.amazonaws.com/dev/slack/events/masseges' \ --form 'email="taro@hoge.com,jiro@hoge.com"' \ --form 'text="[ { \"type\": \"section\", \"text\": { \"type\": \"mrkdwn\", \"text\": \"*twitterフォローしてね!*\" } }, { \"type\": \"section\", \"fields\": [ { \"type\": \"mrkdwn\", \"text\": \"https://twitter.com/Area029S\" } ] } ]"'
送信できました!
あとがき
以上でSlackワークスペースに所属するユーザーに応じて通知を出し分けるAPIを作成することができました。 今後はBoltの認証機能を利用したマルチワークスペース対応の実装例を紹介できればと思います。 ちなみにシンプルに通知のみを実行したいのであればBoltを使わないでサービス側で直接SlackAPIを叩いてしまう方が低コストに実現できます。