LoginSignup
6
1

More than 3 years have passed since last update.

CDKでSlack botを作ろう

Last updated at Posted at 2019-12-04

どうも!@ufoo68です。今回2回目の投稿になります。@keigo1450さんよりバトンパスをもらっての投稿となります。前日のものはかなり実用的で新卒の私はすごく勉強になりました。
そんな私の方は、また作ってみた系になります。

はじめに

この記事が投稿されている頃、今頃私はラスベガスにいることでしょう。ということでAWS関係のことを書こうと思います(そのためにソリューションアーキテクト-アソシエイトとりました)。
あとこの記事は、自分がreinvent中にQiitaを書くというチャレンジで社内のアドベントカレンダーに登録しました。作ったものですが、Slack上で以下のコマンド

/set_money hoge
/check_money

を叩いてカジノの勝ち金を見れるSlackBotを作りました。本当はカジノの戦略考えるBotとか考えましたが、時間と私の知識力により断念。。。

CDKとは

AWS CDKとは、ざっくりと説明すると、AWSのリソース関係のアーキテクチャの構築とか、デプロイとかをプログラム言語で記述できる便利なツールです。詳しい理解はこのチュートリアルを進めるとわかってくるかと思います。

また、このCDKを使ったIoT的なSlackBotを作る記事はすでに公開されています。今回はそれをベースに簡単なおうむ返しSlackBotを作ってみました。
ソースはここで公開しております。

実装

まずは以下のコマンドでテンプレートを準備します

cdk init cdk-slack-bot --language typed

あとはサンプルコードに以下を付け足したり修正したりします。

cdk-slack-bot/lib/cdk-slack-bot-stack.ts
import cdk = require('@aws-cdk/core')
import lambda = require('@aws-cdk/aws-lambda')
import apigw = require('@aws-cdk/aws-apigateway')
import dynamodb = require('@aws-cdk/aws-dynamodb')

export class CdkSlackBotStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    const table = new dynamodb.Table(this, 'Money', {
      partitionKey: { name: 'path', type: dynamodb.AttributeType.STRING }
    })

    const bot = new lambda.Function(this, 'BotHandler', {
      runtime: lambda.Runtime.NODEJS_8_10,
      code: lambda.Code.asset('lambda'),
      handler: 'bot.handler',
      environment: {
        HITS_TABLE_NAME: table.tableName
      }
    })

    table.grantReadWriteData(bot);

    new apigw.LambdaRestApi(this, 'Endpoint', {
      handler: bot
    })

  }
}
cdk-slack-bot/lambda/bot.ts
import * as QueryString from 'querystring'
import { DynamoDB } from 'aws-sdk'

exports.handler = async function (event: any) {
    const query = QueryString.parse(event.body)
    const dynamo = new DynamoDB()
    switch (query.command) {
        case '/set_money':
            if (query.user_name !== 'myname') return {
                statusCode: 200,
                headers: { "Content-Type": "text/plain" },
                body: 'You are not me'
            }
            await dynamo.updateItem({
                TableName: process.env.HITS_TABLE_NAME as string,
                Key: { path: { S: 'money' } },
                UpdateExpression: 'SET money = :num',
                ExpressionAttributeValues: { ':num': { N: query.text as string } }
            }).promise()
            return {
                statusCode: 200,
                headers: { "Content-Type": "text/plain" },
                body: 'Set your total money'
            }
        case '/check_money':
            const money = await dynamo.getItem({
                TableName: process.env.HITS_TABLE_NAME as string,
                Key: { path: { S: 'money' } }
            }).promise()
            return {
                statusCode: 200,
                headers: { "Content-Type": "text/plain" },
                body: `勝ち分は、${money.Item!.money.N}ドルです。`
            }
        default:
            return {
                statusCode: 200,
                headers: { "Content-Type": "text/plain" },
                body: 'invalid command'
            }
    }
}

使ったのはlambda, dynamodb, apigatewayの3つになります。かなり雑な実装ですが、一応私しかset_moneyできないようにガードをかけました(簡単にハックされるとは思いますが)。

さいごに

一応このBotは社内Slackのワークスペースにこっそり入れたのでcheck_moneyで私の勝ち分を確認することができます。まあ、今の所マイナスですが。。。
さて、明日も@keigo1450さんの投稿です。お楽しみに!

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1