LINE Bot x AWS CDKハンズオンに参加して初めてLINE Botを作ってみた

2020.07.07

どーもsutoです。

7/2(木)にAWS CDKを用いたLINE Bot開発のハンズオンに参加してきたのでそのレポートとなります。

LINE Bot開発は初めてなのでこれを機にいままであまり触ってこなかったCDKもついでに経験しようと思い参加しました。今回作成するのは買い物リストBotでした。コードはTypescriptでこちらも自分にとって初使用です。

  • 入力した単語を「買い物リスト」に追加する
  • 「リスト確認」とメッセージを送ると今まで追加した「買い物リスト」の中身を確認することができる
  • 「リストをクリア」とメッセージを送ると今まで今まで追加した「買い物リスト」の中身を削除することができる

こちらのハンズオン資料に従って進めていきます。

ハンズオン環境について

こちらのGitHubのレポジトリを用いますが、ハンズオンではGitpodによる開発環境を起動して進めていきました。これならばローカルの環境を汚さずに済むので自分もGitpodのChrome拡張をインストールして作成しました。(GitHubのログインアカウントが必要なので持ってない方は作成が必要です)

実際にやってみた

LINE Developersの準備

LINE Developerのアカウントを作成し、こちらに記載の手順に従って、 LINE Botチャンネルを作成します。

  • 1-1. LINE Developers にログイン
  • 1-2. プロバイダーを選択
  • 1-3. チャネルを新規作成
  • 1-4. チャネルシークレット をメモしておく
  • 1-6. 応答設定
  • 1-7. チャネルアクセストークン を発行してメモしておく

※「1-5. Webhook 設定」と「1-8. 作成したBotのチャネルを友だち登録する」は後ほど実施します

認証情報の登録

Gitpodの開発環境にAWSの自分のアカウントのCredentialsとLINEのアクセストークン、チャネルシークレットを以下のように設定します。

CDKの実装

yarn

で必要パッケージをインストール

yarn cdk bootstrap

でデプロイのための準備

この後は資料に従ってAPI Gateway、Lambda2件、DynamoDBを実装するためのコードを完成させていきます。

資料はストーリー仕立てで記載されていますが、ぶっちゃけどの段階でどのコードが追加されたのかわかりづらいので、以下コードの完成版にコメントを独自に追記して自分なりにわかりやすくしてみました。

↓のコードを「cdk-line-bot-stack.ts」として保存すればOKです。

lib/cdk-line-bot-stack.ts

import * as cdk from '@aws-cdk/core'
import * as lambda from '@aws-cdk/aws-lambda'
import * as apigateway from '@aws-cdk/aws-apigateway'
import * as dynamodb from '@aws-cdk/aws-dynamodb'


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

      // DynamoDBテーブルの作成
      const table = new dynamodb.Table(this, 'Table', {
        partitionKey: { name: 'userId', type: dynamodb.AttributeType.STRING }
      })

      // 2つのLambdaでlayerのutil関数・npmパッケージを共有するLambda layer
      const layer = new lambda.LayerVersion(this, 'layer', {
        compatibleRuntimes: [lambda.Runtime.NODEJS_12_X],
        code: lambda.Code.fromAsset('layer.out'),
      })

      // 買い物リスト操作用Lambda関数の作成
      const dbHandler = new lambda.Function(this, 'DbHandlerFunction', {
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'index.handler',
        code: lambda.Code.fromAsset('lambda/dbHandler'),
        layers: [layer],
        environment: {    // 環境変数の受け渡し(DynamoDBのテーブル名)
          TABLE_NAME: table.tableName,
        }
      })

      // 会話用Lambda関数の作成
      const linebot = new lambda.Function(this, 'LineBotFunction', {
        runtime: lambda.Runtime.NODEJS_12_X,
        handler: 'index.handler',
        code: lambda.Code.fromAsset('lambda/linebot'),
        layers: [layer],
        environment: {    // 環境変数の受け渡し(認証情報とリスト操作Lambdaの名前)
          ACCESS_TOKEN: process.env.ACCESS_TOKEN!,
          CHANNEL_SECRET: process.env.CHANNEL_SECRET!,
          FUNCTION_NAME: dbHandler.functionName,
        }
      })

      // Lambdaの呼び出し権限のロールを付与
      dbHandler.grantInvoke(linebot)

      // DynamoDBの操作権限のロールを付与
      table.grantFullAccess(dbHandler)

      // API Gatewayの作成
      const api = new apigateway.RestApi(this, 'Api')
      api.root.addMethod('POST', new apigateway.LambdaIntegration(linebot))
    }
  }

あとは

 yarn build
yarn cdk deploy

でデプロイし、成功後に出力されたURLをメモし、LINE Developer画面で

  • 1-5. Webhook 設定と1-8. 作成したBotのチャネルを友だち登録する

を実施すれば完成です。(ハンズオン資料最後のおまけにあるように共通しているコード部分を別ファイルに抜き出して共通ライブラリを作成しても良いでしょう)

AWSのコンソール画面を見るとCloudformation(CFn)に2つのスタックが作成され、各リソースがプロビジョニングされていることが確認できます。

Cloudformation(CFn)でスタックが完了し、各リソースがコマンド1つでデプロイできるのは便利ですね。今回のハンズオンはTypescriptでしたが、言語に限らず普段JavaやPythonのような言語で仕事をしていてCFnのコードに書き慣れていないエンジニアにはCDKでAWSリソースを操作するのも良いですね。

またハンズオン後の後片付けですが、 AWSリソースをしっかり削除するために以下を確認し実施しましょう。

  • CFnで作成されたS3バケット内のフォルダ、ファイルを全て削除する。その後yarn cdk destroyを実行する
  • スタック削除に失敗していたら、手動でCFnテンプレート「CdkLineBotStack」を削除し、次にテンプレート「CDKToolkit」も削除する

まとめ

今回TypescriptもLINE Bot作成も初体験でしたが、体験する機会を自ら作って参加して良かったと思っています。自分の業務での役割はデータ分析や機械学習系の構築ですが、興味のある技術や開発には積極的に挑戦して様々な技術参入へのハードルを下げていこうと思います。