By Tomomi Imura
Published: 2019-11-24
Updated: 2022-02-07
OAuth 権限設定についての変更がありましたので、チュートリアルのその設定部分を編集しました。
今回新しくリリースされた機能、App Home は、ユーザと Slack を1対1で繋ぐことができるスペースで、さらにユーザに直感的にアプリを使ってもらうために加えられた機能なのです。App Home には3つのタブがあり、アプリについての情報をみるための _About_、チャット対話式ボット機能がある場合にそのボットとダイレクトメッセージで会話できる _Messages_、そして今回新しく Home タブが加わりました。
この Home タブは、アプリと各ユーザの間を繋ぐプライベート・スペースで、動的で継続的なコンテンツを提供できるビジュアル・インターフェイスなのです。
もしかしてすでに、ユーザがアプリを開いた時に発生するイベント、 app_home_opened
をご存知かもしれません。以前に紹介した Bolt JavaScript framework チュートリアルの Hello world, Bolt⚡️ Bolt フレームワークを使って Slack Bot を作ろう でも触れられています。今回はさらにそれがバージョンアップして、 Home タブとともに、メッセージだけではなく Block Kit を使って動的なコンテンツを表示するとこが可能になりました。
Google カレンダーの App Home タブ活用例を見てみましょう。
ユーザは Home タブから毎日のカレンダーを見ることができるだけではなく、予定への返答を変更したり、Zoom などのカンファレンス・コールへのジョインなどもここから行うことができるのです。 他、ミーティングなどの予定のある1分前に通知をする機能もついているのです。グーグル、グッドジョブ👍
さて、この App Home をどうやって使うことができるのか、一緒にアプリを制作しながら試してみましょう。ここでは、ユーザがちょっとしたメモをとることができる Stickies(付箋)アプリを作ってみます。
ここでのユーザー・フローは下の通りになります。
ここでのアプリ側のフローは次の通りになります。
app_home_opened
イベントが発生し、アプリのサーバに情報が送信されるviews.publish
メソッドによって、ボタン UI のある初期画面を表示views.open
メソッドで入力フォーム UI のあるモーダルを表示view_submission
のついたもうひとつのインタラクションがトリガーされるviews.publish
メソッドで App Home ビュー表示を更新さて、大まかなフローがわかったところで実際に Stickies アプリを作ってみましょう。 Glitch というサービス上にソースコードを置いてありますので "remix" してみましょう(リミックスとは GitHub の fork のような物、と思ってください)。このサービスではウェブ上でコードのエディットと実行ができますので、デプロイは不要なのでそのまま動かしてみましょう。
まずは Slack アプリの設定をしなければなりません。 Slack App マネージメントからアプリの作成をします。ポップアップが出ますのでそこでアプリの名称を設定し、アプリのインストール可の(=自分がアドミン権限を持つ)ワークスペースを選択してください。
自分がアドミン権限を持つワークスペースをまだお持ちでない場合は新規でワークスペースを作成してから始めましょう。
今度は Features > OAuth & Permissions で Bot トークンのスコープを追加します。chat:write
を選択してください。 (実際にはこのサンプルアプリにはチャットの機能がありませんので、このスコープを使う必要がないのですが、とりあえず追加してください! この最近追加された、以前より細やかになった権限設定については OAuth 2.0, Version 2 ドキュメント (英語)を参照してください。)
次に Features > App Home で、App Home を有効にしてください。
次に Features > Event Subscriptions 画面へ行き、イベントを有効にしてください。(下のスクリーンショットのステップ1参照)。そして Request URL (ステップ 2) を入力します。Glitch 上のコードをリミックスして作業を進めている方は、 Request URL は https://プロジェクト名.glitch.me/slack/events
のようになります。 (Glitch は新規でプロジェクトが作成される毎にプロジェクト名を自動生成します。 通常、ハイフンで繋いだ2つか3つの英単語からランダムに生成されるので、 fluffy-umbrella のようなものになっているはずです。自分でカスタムのプロジェクト名もつけられますので、その際はそのカスタム名を使ってください。自分のサーバを使用している際は、そのURL + /slack/events
にします。)
Request URL 入力が終わったら、Subscribe to bot events までスクロールし、 app_home_opened
イベントを加えてください (ステップ 3)。そして緑の Save Changes ボタンで保存します。(ステップ 4).
次は同じように Features > Interactivity & Shortcuts で Slack サーバにインタラクティブ・ペイロードの送信先を伝える必要があります。 ここでも Request URL を指定してください。URL は https://プロジェクト名.glitch.me/slack/actions
となります。そしてここでも Save Changes ボタンで変更を保存してください。
ここで一度インストールしましょう。 Features > OAuth & Permissions からインストールボタンで自分のワークスペースにこのアプリをインストールします。画面の指定にしたがってインストールしてください。一旦 OAuth を使ってのインストールプロセスが終了しましたら、次の場面でアクセス・トークンが発行されます。
さて、次はブラウザ上で使える IDE の Glitch プロジェクト、またはお使いのコード・エディタに移りましょう。インストール終了時に発行された xoxb-
トークンをコピーし、環境変数ファイル、**.env** の SLACK_BOT_TOKEN
の値としてペーストしてください。
もう一つの環境変数である、 Signing Secret キーは、Slack App マネージメント画面の Settings > Basic information から取得することができます。
このチュートリアルでは、Node.js と Express サーバを使ってアプリを書いています。ここでは全ての API コールは、ごく一般的な HTTP リクエスト、レスポンスで行っていますので、Node 以外の言語をお使いの皆さんにも、ソースコードをみてもらえればどこでどのように API を呼び出しているかわかっていただけるかと思います。
⚡️ もっと簡単に Bolt フレームワークで書きたい!という方のためにも Bolt で書かれたソースコードも用意しています。しかし、このチュートリアルの説明そのものは Bolt や SDK、他のボット・フレームワークを使わない "バニラ" コードでの説明となります。
まず Node コードで、依存モジュールを追加して Express サーバを走らせます。そして raw リクエスト・ペイロードを使ってリクエスト情報の検証をします。詳しい説明は割愛しますが、index.js の 31 - 38 行目を参照してください。 143 -145 行目では Express サーバを実行しています。
リクエスト情報の検証についてもう少し詳しく知りたい方は、以前書いたチュートリアルの Slack メッセージ・ショートカット API を使ってディスカバラブルなアプリを作ろう の中のセクション、🔐 リクエスト情報の検証を読んでみてください。
次に HTTP POST のルーティングメソッドを使って、イベントペイロードを受け取るエンドポイントを定義します(前のステップで設定した、Request URL)。何かのイベントが発生した際にはこのエンドポイントに Slack API からの JSON ペイロード情報が届くので、そこでイベントが app_home_opened
であるかチェックし、そうであれば App Home ヴューを表示させる準備をします。
ここでは、読みやすさを考え、簡略化されたコードスニペットを使っていますが、コードの全てを見たい方は、 index.js 45 - 70 行目)を見てみてください:
app.post('/slack/events', async(req, res) => {
const {type, user, channel, tab, text, subtype} = req.body.event;
if(type === 'app_home_opened') {
displayHome(user);
}
}
さて、ビューの表示には、リッチなコンテンツを Block Kit を使って構築しましょう:
const displayHome = async(user, data) => {
const args = {
token: process.env.SLACK_BOT_TOKEN,
user_id: user,
view: await updateView(user)
};
const result = await axios.post('/views.publish', qs.stringify(args));
};
Home App にコンテンツを表示させるには view.publish
メソッドを使います。 ここでは axios
モジュールをを使って HTTP POST 経由で API を呼び出しています。
ここでの例では、別の関数、updateView
を呼んでコンテンツを JSON で構築しています。この関数は Home ビュー UI を更新する毎に呼びだしています。
初期 UI の設定はこのようになります:
const updateView = async(user) => {
let blocks = [
{
// Section with text and a button
type: "section",
text: {
type: "mrkdwn",
text: "*Welcome!* \nThis is a home for Stickers app. You can add small notes here!"
},
accessory: {
type: "button",
action_id: "add_note",
text: {
type: "plain_text",
text: "Add a Stickie"
}
}
},
// Horizontal divider line
{
type: "divider"
}
];
let view = {
type: 'home',
title: {
type: 'plain_text',
text: 'Keep notes!'
},
blocks: blocks
}
return JSON.stringify(view);
};
blocks
配列部分は、Block Kit をつかったプロトタイプはこちらから見ることができます
実際のコードでは、この関数では、モーダルからユーザ入力された値を使い動的なコンテンツを扱います。この部分は後ほど。
ユーザがボタンをクリックするとモーダルが開きます。
Block Kit メッセージ・ビルディングブロックには action_id
を定義してください。これはデータを受け取る識別子となります。(ここでは add_note
)。
ユーザがボタンをクリックすると API サーバから Request URL に送信されるこのアクションについてのペイロードには trigger_id
が含まれます。これはモーダルを開くための識別子となります。
app.post('/slack/actions', async(req, res) => {
const { token, trigger_id, user, actions, type } = JSON.parse(req.body.payload);
if(actions && actions[0].action_id.match(/add_/)) {
openModal(trigger_id);
}
});
次に入力フォーム・エレメントを、モーダルの中に表示しましょう。この例ではごくシンプルに、付箋にメモするテキストを入力するマルチライン(複数行)インプット・ボックスと、付箋の色を指定するドロップダウン・メニューを表示させます。
モーダルを表示させるには views.open
メソッドを呼びます:
const openModal = async(trigger_id) => {
const modal = {
type: 'modal',
title: {
type: 'plain_text',
text: 'Create a stickie note'
},
submit: {
type: 'plain_text',
text: 'Create'
},
blocks: [
// Text input
{
"type": "input",
"block_id": "note01",
"label": {
"type": "plain_text",
"text": "Note"
},
"element": {
"action_id": "content",
"type": "plain_text_input",
"placeholder": {
"type": "plain_text",
"text": "Take a note... "
},
"multiline": true
}
},
// Drop-down menu
{
"type": "input",
"block_id": "note02",
"label": {
"type": "plain_text",
"text": "Color",
},
"element": {
"type": "static_select",
"action_id": "color",
"options": [
{
"text": {
"type": "plain_text",
"text": "yellow"
},
"value": "yellow"
},
{
"text": {
"type": "plain_text",
"text": "blue"
},
"value": "blue"
}
]
}
}
]
};
const args = {
token: process.env.SLACK_BOT_TOKEN,
trigger_id: trigger_id,
view: JSON.stringify(modal)
};
const result = await axios.post('/views.open', qs.stringify(args));
};
一見長いコードですが、ほとんどは JSON で UI を描いているだけです。Block Kit プロトタイプはここから見ることができます。
ユーザからのフォーム・サブミッションのハンドリングは、ボタンクリックのハンドリングと同じようにすることができます。
モーダル内のフォームがサブミットされた際には、このアクションのエンドポイントにペイロードが届きます。ボタンクリック時と区別するにはペイロードに含まれる type
の値をチェックしてください:
app.post('/slack/actions', async(req, res) => {
const { type, user, view } = JSON.parse(req.body.payload);
else if(type === 'view_submission') {
res.send(''); // Make sure to respond to the server to avoid an error
const data = {
note: view.state.values.note01.content.value,
color: view.state.values.note02.color.selected_option.value
}
displayHome(user.id, data);
}
});
この部分のコード全てを見るには index.js 107 - 133 行を参照してください。
ここでユーザから追加されたデータを元のデータに追加して、 Home タブの内容を
views.publish
メソッドと使って書き換えます。
このサンプルコードでは、単純化するために永続データの格納に node-json-db
モジュールを使用しています。ユーザが新しいメモを追加する毎に、そのデータが下のデータ配列にプッシュされていきます。
その新しいデータを、元の JSON にアペンドしてできた新たな UI ブロックを、 views.publish
メソットで再表示しています。
実際のソースコードは appHome.js の 17 - 152 行をみてみてください。このあたりは自分の好きなように処理してみてください。
さて、これで一通りアプリが動くはずですので試してみましょう。Slack クライアントのサイドメニューの App でみられるアプリ一覧からこの Stickies! アプリを探してクリックしてみてください。無事、App Home が表示されましたか?
Add a Stickie ボタンを押して、新しい付箋が Home ビューに反映されたか確認してみてください。🎉
さて、このチュートリアルが、新しいアプリを作る、もしくは既存のアプリをアップデートするためのインスピレーションになっていただけたらうれしいです。
ご質問やコメントがありましたら、開発者サポート (@SlackAPI または support@slack.com) までご連絡ください。