Slack Boltからmessage buttonsとmenusを使う


こんにちは、 @hico_horiuchi です。
先日、会社の昼休みLT会(通称#random-jp会)でBoltを紹介したので、そのまとめです。

目次

  • Boltとは?
  • Hello Worldをやってみる
  • message buttonsを使う
  • message menusを使う
  • まとめ

Boltとは?

Bolt はSlack社が開発しているSlack Appのフレームワークです。
(Botだけでなく、Slash Commandなども簡単に開発できるようになっています。)

2019年4月にv1.0.0がリリースされたばかりの、比較的新しいOSSです。
Release Introducing Bolt - v1.0.0

Hello Worldをやってみる

最初に「hello」に対して「Hey there @hiconyan!」と返す機能を作ってみます。
Slack Appの作成方法などは、下記の公式情報を参考にすると分かりやすいです。

今回はBotの名前を「boltnyan」にしてみました。
BotkitでHubotみたいにscriptsを読み込む と同様のファイル構成にしています。

サンプルコードはこちら: hico-horiuchi/boltnyan

boltnyan/
  bin/
    bolt
  node_modules/
  scripts/
    hello.js
  package.json

hello.jsはこちらです、とても簡単ですね。
(Slack Appで イベントの設定 をするのをお忘れなく。)

scripts/hello.js
app.message(`boltnyan hello`, ({ message, say }) => {
  say(`Hey there <@${message.user}>!`);
});

bin/bolt を実行して boltnyan hello を声をかけると、挨拶が返ってきました。

message buttonsを使う

Boltを使うと message buttons も簡単に実装することができます。

say()attachments[].callback_id でbuttonに識別子を付けて(ここでは game_button )、
それを action() で指定することで、ユーザが該当のbuttonをクリックしたときのレスポンスを受け取ることができます。

ack() でattachmentsを返すことで、該当のボタンを含むメッセージを書き換えることもできます。

scripts/button.js
app.message('boltnyan button', ({ message, say }) => {
  say({
    text: 'Would you like to play a game?',
    attachments: [{
      text: 'Choose a game to play',
      fallback: 'You are unable to choose a game',
      callback_id: 'game_button',
      color: '#3AA3E3',
      attachment_type: 'default',
      actions: [{
        name: 'game',
        text: 'Chess',
        type: 'button',
        value: 'chess'
      }, ...]
    }]
  });
});

app.action({ callback_id: 'game_button' }, ({ body, ack, say }) => {
  let user = body.user.id;
  let value = body.actions[0].value;

  ack({
    text: 'Would you like to play a game?',
    attachments: [{
      text: `Choose a game to play¥n¥n<@${user}> clicked ${value}`,
      color: '#3AA3E3',
      attachment_type: 'default',
    }]
  });
});

boltnyan button でbuttonを表示させて「Chess」をクリックすると、このようになります。

message menusを使う

message buttonと同様に message menus も実装してみます。

callback_id として game_menu を指定して、ユーザが該当のmenuを選択したときのレスポンスを受け取っています。
say() で投稿する場合のattachmentsの構造や ack() で受け取る body.actions[] の構造が違うので注意してください。

scripts/menu.js
app.message('boltnyan menu', ({ message, say }) => {
  say({
    text: 'Would you like to play a game?',
    response_type: 'in_channel',
    attachments: [{
      text: 'Choose a game to play',
      fallback: "If you could read this message, you'd be choosing something fun to do right now.",
      color: '#3AA3E3',
      attachment_type: 'default',
      callback_id: 'game_menu',
      actions: [{
        name: 'games_list',
        text: 'Pick a game...',
        type: 'select',
        options: [{
          text: 'Hearts',
          value: 'hearts'
        }, ...]
      }]
    }]
  });
});

app.action({ callback_id: 'game_menu' }, ({ body, ack, say }) => {
  let user = body.user.id;
  let value = body.actions[0].selected_options[0].value;

  ack({
    text: 'Would you like to play a game?',
    attachments: [{
      text: `Choose a game to play¥n¥n<@${user}> selected ${value}`,
      color: '#3AA3E3',
      attachment_type: 'default',
    }]
  });
});

boltnyan menu でmenuを表示させて「Chess」を選択すると、このようになります。

まとめ

実はbuttonsとmenusが非推奨になり blocks に移行していることを、この記事を書いている最中に知りました…。
次回はBoltとblocksの連携や、Hubotで同様の機能を実装する方法についてご紹介したいと思います。