By Tomomi Imura
Published: 2019-03-28
Updated: 2022-01-31
OAuth 権限設定についての変更がありましたので、チュートリアルのその設定部分の編集しました。
こんにちは、みなさんいかがお過ごしですか。さて最近、Slack の新しいメッセージ UI フレームワーク Block Kit がリリースされました。これを使えば皆さんの Slack アプリから送信できるメッセージがさらにリッチになり、例えばタスクのリストや投票結果などが一つのメッセージでより情報的になります。
Block Kit は、ビジュアルツール Block Kit Builder を使うとさらに簡単にプロトタイプでき、さらにこのツールで生成された JSON ストリングをコードにそのまま組み込むことができます。
このチュートリアルでは、検索結果を閲覧するユーザー体験を Block Kit を使ってメッセージを組み立てることでよりよくするための手順を紹介していきたいと思います。
このチュートリアルでは Node.js を使って Slash Command アプリを作成していきます。JavaScript または他のプログラミング言語の経験が必要です。
コードは、ブラウザ上でコードを実行できデプロイの必要もない、ウェブ IDE である Glitch を使用します。
まずは下のリンクから “remix” して始めましょう。リミックスとは GitHub でいう Fork のようなものだと思ってください。
🎏🥫 ソースコード: https://glitch.com/edit/#!/slash-blockkit
🎏🍴 Remix のリンク: https://glitch.com/edit/#!/remix/slash-blockkit
それから、ここではこのアプリをもっとおもしろくするために Yelp API を使用していますので、このサイトから Yelp Client ID と API key を取得してください。詳しくは Yelp ディベロッパー・サイトから。
では始めましょう。このアプリ上でのユーザーの手順は次の通りです。
/find-food [食のジャンル], [場所]
(例 /find-food burrito, San Francisco
) とコマンドを入力まずは /find-food
コマンドに応答してごくシンプルなテキストを返す、という Slash command から作っていきましょう。
まずは Slack App マネージメント でアプリの作成をします。
次に slash command を加え、そのコマンド情報を入力します。ここでは /find-food
としてみましょう。使われるパラメータは、食べ物と場所をコンマで区切った短い文になります。例えば /find-food pancake, shibuya
のようになります。
コマンドを有効にすることによって commands
という bot 権限スコープが自動的に追加されます。
Request URL は https://your-server/route
となりますので Glitch から “remix” した際は Glitch がランダムな単語ふたつからなるプロジェクトネームを生成しますので、Request URL は https://sassy-shrimp.glitch.me/command
のような感じになります。
次に Settings > Basic information で Signing Secret key を取得します。
このキー情報と、Yelp API の認証情報は、🗝 .env ファイルに保管します。
SLACK_SIGNING_SECRET=fca39e3de...
YELP_CLIENT_ID=sIskJpLm5f...
YELP_API_KEY=ySz84qKNl...
(Glitch 上のサンプルコードには .env.sample というファイルを用意してあるので、それを .envにコピーし、認証情報を入力してください。)
下の Node.js コードでは依存するモジュールをインポートし、 Express サーバを動かしています。それからここでは、リクエスト署名(Signing Secret)を検証するために、リクエスト・ペイロードをそのまま受け取っています。(詳しくはこの日本語記事と、チュートリアルから。)
const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const signature = require('./verifySignature');
const app = express();
const rawBodyBuffer = (req, res, buf, encoding) => {
if (buf && buf.length) req.rawBody = buf.toString(encoding || 'utf8');
};
app.use(bodyParser.urlencoded({verify: rawBodyBuffer, extended: true }));
app.use(bodyParser.json({ verify: rawBodyBuffer }));
const server = app.listen(process.env.PORT || 5000);
次に HTTP POST メソッドルートを使って Slash command のリクエスト・ペイロードを受け取るためのエンドポイントを作ります。受け取りの時にそのリクエストが正規に Slack からきているものかを確認します。検証結果が問題なかった場合にのみ、ユーザからのパラメータを受け取って、パースします。この場合、食べ物のジャンルと場所のクエリを受け取ります。
そのクエリを Yelp API に投げ、その結果を受け取ります。
app.post('/command', async (req, res) => {
if(!signature.isVerified(req)) {
res.sendStatus(404);
return;
} else {
const query = req.body.text ? req.body.text : 'lunch, San Francisco';
const queries = query.split(',');
const term = queries.shift(); // "Pizza"
const location = queries; // "San Francisco, CA"
const places = await getPlaces(query, location);
}
const message = { // will generate it }
res.json(message);
}
このコードでは getPlaces()
関数で Yelp API から結果をうけとる仕組みにしています。 (詳しくはソースコードを見てください。)
Yelp REST API から返された結果の JSON 配列は次のような感じになります。(チュートリアルをわかりやすくするために、 JSON の内容を簡略化しています)
[{
name: 'Zero Zero',
image_url:
'https://s3-media2.fl.yelpcdn.com/bphoto/JB5XNOgdQHocE4nI9DHWkA/o.jpg',
url:'https://www.yelp.com/biz/zero-zero-san-francisco',
review_count: 3128,
rating: 4,
price: '$$',
location:
{
display_address: [ '826 Folsom St', 'San Francisco, CA 94107' ] },
phone: '+14153488800'
}...
]
まず、この情報の一部を使って、コマンドを送信したユーザーにごく簡単なメッセージを返してみましょう。サーバには HTTP 200 のレスポンスをすれば良いのですが、この場合は JSON を返しましょう。Slack チャンネル上に全ユーザーに見えるようにメッセージする場合は下のような JSON を送信します。
const message = {
response_type: 'in_channel',
text: places[0].name,
};
res.json(message);
このレスポンスは Slack 上ではこう表示されます。
さて、次は Block Kit エレメントで、このメッセージを、もっと情報の入った読みやすいメッセージにしましょう。
Block Kit は、組み立て可能のレイアウトやエレメントといったブロックで構成されています。
今からこれを使って、メッセージレイアウトを構成する JSON に書き換え、リッチなメッセージでレストラン情報を表示させましょう。
ビジュアル・サンドボックスである Block Kit Builder を使ってブラウザ上でデザインをプロトタイプしていきましょう。
左側にあるメニューからレイアウトもしくはエレメントを選んでいくと、真ん中にはプレビューが、右には生成された JSON 配列が表示されます。
生成されたコードをコピーして、前のコードの message
オブジェクトの text: places[0].name
部分を下のように block
として書き換えます。
const message = {
response_type: 'in_channel',
blocks: [
// Result 1
{
type: 'section',
text: {
type: 'mrkdwn',
text: `*<${places[0].url}|${places[0].name}>* \n${places[0].location.display_address.join(' ')} \n\nRating: ${places[0].rating} \nPrice: ${places[0].price}`
},
accessory: {
type: 'image',
image_url: `${places[0].image_url}`,
alt_text: 'venue image'
}
},
{
'type': 'context',
'elements': [
{
'type': 'plain_text',
'text': `${places[0].review_count} Yelp reviews`,
'emoji': true
}
]
},
{
'type': 'divider'
},
}
]
};
エレメントで text type 部分を mrkdwn
とすることによってテキストに太字やリンクなどのマークダウンをしようすることもできます。詳しくは An overview of message composition(英語)から。
では、できあがった Slash command をクライアント上で試してみましょう!こんな感じに表示されましたか?🙆
いぇ〜い! でもなんだか、お腹すいてきたわ。
さて、今回は Slash command の結果をリッチ・メッセージで送信してみましたが、他にもいろいろな機能を一緒に使えます。例えば incoming webhooks、Web API の chat.postMessage
や chat.postEphemeral
メソッドで送信できます。アクションなどのインタラクティブ機能にも使うことができます。
Block Kit Builder 上でメッセージレイアウトやエレメントをいろいろ試してみてクリエイティブなメッセージ UI を試してみてください。プロトタイプで遊んでみるのは大いに推奨しますが、ここで気をつけてもらいたいのは、実際のプロダクトとなる UI を構築するにはまず何よりもユーザーを第一に考えてください。メッセージは読みやすいものでなくてはなりません。可能だからと言って何もかも詰め込むのはよくありません。内容が多くなってしまう場合には、たとえば “Read more…” など、さらなるユーザーアクションを促すボタン機能などを追加するのもいいかもしれません。 いろいろプロトタイプを作ってテストしてみましょう。モバイルでのテストも忘れないでください。
このチュートリアルによって、なにか新しいアイデアが浮かんだり、前に作ったアプリの改良などをしてみたい、と思ってくれていたら幸いです!
ご質問やコメントがありましたら、開発者サポート (@SlackAPI または support@slack.com) までご連絡ください。