moto blog

AWS(API Gateway + Lambda(Python)) + Slack APIを使ったBot作成

f:id:nmmmk:20181010001356p:plain

AWS(API Gateway + Lambda(Python)) + Slack APIを使って、Botを作成します。 作成するのは、メンションを受けて、固定メッセージを返信する簡単なBotです。

構造

システム構成は、以下のようにします。
Slack APIとしては、Event APIを利用します。
f:id:nmmmk:20181009222445p:plain

Lambda関数の作成

  1. サービスからLambdaを選択する。
    f:id:nmmmk:20181009224013p:plain

  2. 関数を作成する。
    f:id:nmmmk:20181009224817p:plain

  3. 「一から作成」を選択する。
    f:id:nmmmk:20181009224902p:plain

  4. 以下の様に各項目を入力する。
    f:id:nmmmk:20181009224931p:plain

  5. Lambdaのソースコード編集画面にて、SlackのEvent APIの認証のため、以下のコードに変更する。
    f:id:nmmmk:20181009225000p:plain

def lambda_handler(event, context):
    
    # SlackのEvent APIの認証
    if "challenge" in event:
        return event["challenge"]
    
    return "OK"    

  6. API Gatewayをトリガーとして追加する。
f:id:nmmmk:20181009225021p:plain

  7. トリガーの設定で「新規APIの作成」を押下する。
f:id:nmmmk:20181009225044p:plain

  8. 各項目を以下の様に設定する。
f:id:nmmmk:20181009225108p:plain

  9. 画面右上の保存ボタンを押下する。
f:id:nmmmk:20181009225134p:plain

  10. API Gatewayの設定が確定する。
f:id:nmmmk:20181010000036p:plain

API Gatewayの設定

  1. SampleBotのリンクを押下して、API Gatewayの設定画面を表示する。
    f:id:nmmmk:20181010000051p:plain

  2. 「/SampleBot」を選択して、アクションからメソッドの作成を選択する。
    f:id:nmmmk:20181009234138p:plain

  3. POSTを選択後、チェックを押下する。
    f:id:nmmmk:20181009234157p:plain

  4. 「ANY」を選択して、アクションからメソッドの削除を選択する。
    f:id:nmmmk:20181009234225p:plain

  5. 「POST」を選択後、以下の様に設定して、保存ボタンを押下する。
    統合タイプ:Lambda関数
    Lambda関数:SampleBot
    f:id:nmmmk:20181009234300p:plain

  6. 「POST」を選択後、アクションからAPIのデプロイを選択する。
    f:id:nmmmk:20181009234316p:plain

  7. デプロイされるステージに、ここでは、「prod」と入力し、デプロイボタンを押下する。
    f:id:nmmmk:20181009234336p:plain

  8. 「/POST」を選択すると、URLが生成されているため、このURLをコピーしておく。
    f:id:nmmmk:20181009234356p:plain

  9. Lambdaの画面を再表示し、API Gatewayを選択する。以下の様に、設定が2つになっているため、/*/*/SampleBotの方を削除する。
    f:id:nmmmk:20181009234410p:plain

  10. 右上の保存ボタンを押下して、削除を確定する。
    f:id:nmmmk:20181009234436p:plain

Slackのアプリ作成

  1. 以下にアクセスする。
    https://api.slack.com/apps

  2. Create New Appボタンを押下する。
    f:id:nmmmk:20181009234500p:plain

  3. App NameとDevelopment Slack Workspaceを設定する。
    f:id:nmmmk:20181009234608p:plain

  4. Bot Usersメニューを表示し、Add a Bot Userボタンを押下する。
    f:id:nmmmk:20181009234624p:plain

  5. 以下の赤枠の様に設定する。
    f:id:nmmmk:20181009234640p:plain

  6. Event Subscriptionsメニューを表示する。
    f:id:nmmmk:20181010214448p:plain

  7. 設定をOnにし、Request URLに、API Gateway設定時に生成したURLをペーストする。正しく疎通できていれば、「Verified」と表示される。
    f:id:nmmmk:20181009234800p:plain

  8. そのまま下にスクロールして行き、Subscribe to Bot Eventsの設定を行う。Add Bot User Eventを押下し、「app_mention」を選択する。最後に、Save Changesボタンを押下する。
    この設定により、botに対してメンションされた場合に、イベントがAWSの方に通知されるようになる。 f:id:nmmmk:20181009234817p:plain

  9. Install Appメニューを表示し、Install App to Workspaceボタンを押下する。
    f:id:nmmmk:20181009234835p:plain

  10. 以下の様に確認メッセージが表示されるため、許可するボタンを押下する。
    f:id:nmmmk:20181009234850p:plain

Lambdaの設定

環境変数設定

以下の様に設定する

環境変数
SLACK_BOT_USER_ACCESS_TOKEN SlackのBot User OAuth Access Tokenの値
SLACK_BOT_VERIFY_TOKEN SlackのVerification Tokenの値

f:id:nmmmk:20181009233939p:plain

ソースコード

# -*- coding: utf-8 -*-
import os
import logging
import json
import urllib.request

# ログ設定
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    
    # 受信データをCloud Watchログに出力
    logging.info(json.dumps(event))

    # SlackのEvent APIの認証
    if "challenge" in event:
        return event["challenge"]
    
    # tokenのチェック
    if not is_verify_token(event):
        return "OK"    
    
    # ボットへのメンションでない場合
    if not is_app_mention(event):
        return "OK"    
    
    # Slackにメッセージを投稿する
    post_message_to_channel(event.get("event").get("channel"), "Hello, Slack Bot!")

    return 'OK'


def post_message_to_channel(channel, message):
    url = "https://slack.com/api/chat.postMessage"
    headers = {
        "Content-Type": "application/json; charset=UTF-8",
        "Authorization": "Bearer {0}".format(os.environ["SLACK_BOT_USER_ACCESS_TOKEN"])
    }
    data = {
        "token": os.environ["SLACK_BOT_VERIFY_TOKEN"],
        "channel": channel,
        "text": message,
    }

    req = urllib.request.Request(url, data=json.dumps(data).encode("utf-8"), method="POST", headers=headers)
    urllib.request.urlopen(req)

def is_verify_token(event):

    # トークンをチェック    
    token = event.get("token")
    if token != os.environ["SLACK_BOT_VERIFY_TOKEN"]:
        return False

    return True
    

def is_app_mention(event):
    return event.get("event").get("type") == "app_mention"

実行する

f:id:nmmmk:20181009235331p:plain