2018年8月8日水曜日

Slack Event API を利用した Bot を LogicFlow で作成する

Slack でメッセージが投稿された際に、外部を呼び出す仕組みとして OutGoing Webhook がありますが、こちらはどこで廃止するかわからない状態へと変わったのもあり、今後は Event API など別の仕組みを利用する必要がありました。

image

今回は Event API の仕組みを利用して、Slack で投稿されたら反応する Bot を LogicFlow で組んでみました。

1.Slack アプリケーションの登録

Event Api を利用するために、まずは Slack に対してアプリケーションの登録が必要です。

image

Slack API にアクセスして、アプリの登録を行います。上記スクリーンショットで表示されている「Create a Slack app」と表示されている緑色のボタンをクリックします。

image

上記のようなダイアログが表示されるので、App Name には適当なアプリケーション名を、Development Slack Workspace には Bot が動作するワークスペースを選択します。

image

値を入力すると、右下の「Create App」がクリック可能になるので、クリックします。

image

アプリケーションの登録が行われると、上記のような画面が表示されます。今回は Event API を利用したやりとりを行うので、Event Subscriptions をクリックします。

image

ここで Off となっているトグルを On にすることで Event API が有効化されます。

image

そこから先の設定では、Event API で呼び出す先の URL が必要になったりしますので、Slack 側の設定は一度ここで区切ります。

2.LogicFlow の作成 第一弾

image

Azure Portal から新しく LogicApps を作成、または Flow にて新しく作成を行います。題目にある「第一弾」というのが色々感じるかと思いますが、Slack の Event API を利用する際、送り先 URL の検証をクリアする必要があり、その時のやり取り用処理を先に用意する必要があるためです。

その際に、送られてきた値を元に手億艇のルールにのっとって返答を返す必要があります。実際に送られてくる値については、API ドキュメントでサンプルがありますので、これをもとに受け取るデータのスキーマを定義するよう LogicFlow の設定を行っていきます。

サンプル値
{
"token": "適当なトークン値",
"challenge": "適当な値",
"type": "url_verification"
}

image

最初の段階で必要な LogicFlow は上記のように、HTTP の要求を受けるトリガと返答するアクションの二つだけです。

image

サンプルデータをもとに、スキーマを定義します。

image

API ドキュメントを参考にして、この際に戻す値を設定します。戻し方は何種類かありますが、今回は text/plain の形式で対応する方法を行います。この場合は、本文として受け取った challenge の値をそのまま返却することが必要です。

image

先ほど定義したスキーマにより、ダイアログで challenge が選択できますので、それを本文に設定します。ここを設定したら一度保存し、HTTP 呼び出しを行える URL を生成してもらいます。

image

この URL を Slack の Event API 設定に設定する必要がありますので、今度は Slack 側に戻ります。

3.Slack Event API の設定

Slack 側に戻ったら。Event Api を利用するよう各種設定を行います。

image

左側メニューの Bot User をクリックすると、上記のように表示されますので Add a Bot User をクリックします。

image

次に、Slack 上でどう表示されるかといった部分を設定します。Display Name が表示される名前、Default Username は Slack 上で扱う際の基本ユーザーアカウント、Always Show My Bot as Online は、Bot がオンラインであると常に表示するかどうかの選択です。

設定したら、下にある緑色な Add Bot User をクリックします。追加が行われると、今のボタンの周りの表示が変わりますが、特にクリックしなくても大丈夫です。

次に Event Subscription の設定を行います。左メニューの Event Subscription をクリックします。

image

まずは Off になっている設定を On にします。すると設定が必要な個所が表示されます。

2 で作成した LogicFlow の URL を、Event API の設定にある Request URL 欄に貼り付けます。張り付けると、実際にその URL が有効かどうかを Slack 側から呼び出しをかけ、先ほど作成した LogicFlow が呼び出されます。

image

問題なくアクセスが確認できれば、上記のように Verified と表示されます。ここで何らかの問題があった場合は、URL の張り付けミスか、LogicFlow の内容を確認してみてください。

image

LogicFlow 側でもこのように、Slack 側からの呼び出しが履歴に確認できています。ここに呼び出し履歴が確認できない場合、Logic Apps であればワークフロー設定のアクセス制御で、呼び出し元の制限をかけているかどうかをチェックしてください。Flow の場合は基本的に呼び出せるはずです。

image

続いて Bot に送信してもらうイベント種類を設定します。今回はメッセージの取得が行えればまずはよいので、message.channels というイベントを選択します。ここで選択したイベントが、Bot 側へ通知されるものとなります。

image

ここまで設定したら、画面の一番下にある Save Changes をクリックして、設定を保存します。ここで保存しないと後で泣きます。

image

保存が行われたら、左メニューの Install App をクリックし、アプリケーションを Slack 上で利用できるように登録します。

image

ここで緑色の Install App to Workspace をクリックします。

image

すると上記のように、アプリを登録する際に与えられる権限が表示されます。今時点ではそのまま 許可する をクリックします。

image

設定が終わると、OAuth のトークンが表示されますが、今回は使用しませんのでスルーして大丈夫です。これで Slack 側の設定は一通り終了です。

4.LogicFlow の作成 第二弾

いよいよ Bot として動く部分の LogicFlow を作成します。すでに HTTP での要求に対するトリガと、返答を返すアクションが定義されている状態から変更していきます。

まずは送信されるデータの内容をスキーマ定義します。API ドキュメントを参考に作業を行います。

image

理想としては、ここにあるサンプルデータをもとにスキーマ定義してそれで万事OK、となるのがよいのですが、残念ながらそううまくは行きません・・・。

今回の message.channel イベントのデータですが、上記サンプルでは記載されていない値があり、しかもそれが今回の処理で必要となるものだったりします。このあたりですが、開発を経験している人でなくては難しいところになっているのが残念です。

{
     "token": "************************",
     "team_id": "*********",
     "api_app_id": "*********",
     "event": {
         "text": "Bot の発言やで",
         "username": "Microsoft Azure Logic-Apps",
         "bot_id": "*********",
         "type": "message",
         "subtype": "bot_message",
         "ts": "1533689573.000015",
         "channel": "*********",
         "event_ts": "1533689573.000015",
         "channel_type": "channel"
     },
     "type": "event_callback",
     "event_id": "EvC5TP1W30",
     "event_time": 1533689573,
     "authed_users": [
         "*********"
     ]
}   

例えば上記のデータは「Bot が発言した際のイベントデータです。event の中に色々ありますが、API ドキュメントにあるサンプルには記載されていない値「bot_id」と「subtype」があります。Bot を作る際にはこの辺りに注意が必要で、送信されるデータをすべて一つにまとめたものから、スキーマを作成する必要があります。今回作成したスキーマを以下に記載しておきますので、こちらも利用してみてください。

{
     "properties": {
         "api_app_id": {
             "type": "string"
         },
         "authed_teams": {
             "items": {
                 "type": "string"
             },
             "type": "array"
         },
         "challenge": {
             "type": "string"
         },
         "event": {
             "properties": {
                 "bot_id": {
                     "type": "string"
                 },
                 "channel": {
                     "type": "string"
                 },
                 "channel_type": {
                     "type": "string"
                 },
                 "event_ts": {
                     "type": "string"
                 },
                 "subtype": {
                     "type": "string"
                 },
                 "text": {
                     "type": "string"
                 },
                 "ts": {
                     "type": "string"
                 },
                 "type": {
                     "type": "string"
                 },
                 "user": {
                     "type": "string"
                 },
                 "username": {
                     "type": "string"
                 }
             },
             "type": "object"
         },
         "event_id": {
             "type": "string"
         },
         "event_time": {
             "type": "integer"
         },
         "team_id": {
             "type": "string"
         },
         "token": {
             "type": "string"
         },
         "type": {
             "type": "string"
         }
     },
     "type": "object"
}

さて、感の良い人であれば不足していた値の名称から気づくかもしれませんが、Event API では Bot が発言したこともイベントとして通知されます。そのため、Bot が自分自身の発言に反応するのを防ぐ処置を用意していないと、無限ループとなり延々と同じ発言を続けてしまうので注意が必要です。

image

そこを判断するための材料に、先ほど不足していると書いた subtype の値を利用します。

image

受信したデータに対して subtype の値が bot_message だった場合、Bot による発言を意味しますので何も処理を行わずに終了する必要があります。

そのあたりも踏まえて、以下のような LogicFlow を作成しました。

image

ポイントとなるところは、

  1. Botから返答する前に応答を返している
  2. ユーザーの発言かどうかを判定している箇所

の2点です。まず最初に応答を返している点ですが、これをやっておかないと Slack 側で HTTP 通信に失敗した、と判断されて何度もリトライされます。

image

応答では特に何も設定せずに、状態コード 200 で結果を返すようにしてください。これが Slack 側で正常に送信できたことを確認できるものとなります。

image

次にメッセージの判断を行っている部分ですが、subtype はまだいいのですが問題は type の方です。Slack から送信される値で type という値は 2 つあり、どちらを選択しているかがデザイナ上では全く分かりません。Logic Apps の場合は CodeView を利用することで確認が可能です。

image

上記のようにトリガで受け取った値の直下、triggerBody()?[‘type’] となるように設定してください。Flow の場合は CodeView 相当のものがないので、片方で試してダメだったらもう片方、もしくはエクスポートして直接上記の個所を書き換えるなど必要です・・・。

image

このようにすることで、Slack Event API を利用した Bot を LogicFlow で構築することが可能です。

最後に注意ですが、Slack から Bot へ通知されるイベントは、結構な頻度となります。そのため Flow では対応できるけどもあまり向いていない類となりますので、このような場合は Logic Apps で対応するのがよいと思います。

0 件のコメント:

コメントを投稿