AWS Lambda+ServerlessでSlack APIのEvent Subscriptionsを使用する(ServerlessでAPIを作る)

技術備忘録

このページではSlackで特定のチャンネルでの自分宛のメッセージを受信時に対して自動的に応答するボットのためのAPIをServerlessで実装することを目的としています。

Slack APIの設定はこちらから

ソースコードはこちら

スポンサーリンク

作りたいもの

特定のチャンネルで自分にメンションが来たメッセージに対して、「了解」と返信するボット

ここでは、返信するのはボットですが、ユーザが返信をしているように見せます。

スポンサーリンク

Serverlessのインストール&AWS認証情報登録

# インストール
npm install -g serverless

# AWS認証情報の登録
serverless config credentials --provider aws --key {access_key} --secret {secret_key}
スポンサーリンク

python3のテンプレートを使用する

sls create -t aws-python3 -p test-api
スポンサーリンク

serverless.yml

service: lambda-api
frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  region: ap-northeast-1
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - s3:ListBucket
        - s3:GetObject
        - logs:CreateLogGroup
        - logs:CreateLogStream
        - logs:PutLogEvents
      Resource:
        - "arn:aws:s3::*"

functions:
  slack_bot:
    handler: handler.handler
    memorySize: 2048
    timeout: 60
    environment: ${self:custom.environment.${self:provider.stage}}
    events:
      - http:
          path: api/lambda-api
          method: post
      - schedule:
          name: periodic_execution_5min  # コールドスタート対策として,5分ごとにCloudWatchでアクセス
          description: 'periodic_execution'
          rate: rate(5 minutes)
          input: '{"cron":"cron"}'
          enabled: true

plugins:
  - serverless-python-requirements

custom:
  defaultStage: dev
  environment:
    dev: ${file(env/.dev.yml)} # 環境変数の設定先

  pythonRequirements:
    dockerizePip: true
スポンサーリンク

handler.py

try:
    import unzip_requirements
except ImportError:
    pass
import json, requests, os
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
SLACK_USER_ACCESS_TOKEN = os.environ['SLACK_USER_ACCESS_TOKEN']
TARGET_CHANNEL = os.environ['TARGET_CHANNEL']
ME = os.environ['ME']

TARGET_CHANNEL = '' # 監視するチャンネルのID
ME = '' # 自分宛のメッセージを監視

def handler(event, context):
    logging.info(event)

    if 'cron' in event: # コールドスタート対策でCloudWatchからの定期的な呼び出しに対応
        return {
            'statusCode': 200,
            'body': 'cron'
        }

    if 'challenge' in event['body']: # Event Subscriptionsでエンドポイント登録時に必要
        body = json.loads(event['body'])
        logging.info(body)
        return {
            'statusCode': 200,
            'body': body['challenge']
        }

    body = json.loads(event['body'])
    if 'event' in event['body']:
        if body['event']['channel']==TARGET_CHANNEL:
            channel = body['event']['channel']
            text = body['event']['text']
            threadTs = body['event']['ts']
            if ME in text:
                postReply(channel, '了解', threadTs)
            return {
                'statusCode': 200,
                'body': text
            }

    return {
            'statusCode': 200,
            'body': 'end'
        }

def postReply(channel, text, threadTs):
    url = 'https://slack.com/api/chat.postMessage'
    headers = {
        'Authorization': 'Bearer ' + SLACK_USER_ACCESS_TOKEN
    }
    params = {
        'channel': channel,
        'as_user': True,
        'text': text,
        'thread_ts' : threadTs
    }
    res = requests.post(url, params=params, headers=headers)
    logging.info(res.json())
スポンサーリンク

環境変数の設定

User OAuth Tokenを指定する

SLACK_USER_ACCESS_TOKEN: xoxp-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
TARGET_CHANNEL: '{対象とするチャンネルのID}'
ME: '{受信者のID}'
スポンサーリンク

デプロイ

serverless-python-requirementsをインストールしておく

npm install --save serverless-python-requirements

dockerを起動しておく

sls deploy

コメント

タイトルとURLをコピーしました