AWS SAM+TypeScriptでLINE Bot のサンプルを作成してみました(小ネタ)

127件のシェア(ちょっぴり話題の記事)

1 はじめに

AIソリューション部の平内(SIN)です。

サーバ側にAWS LambdaAPI Gatewayを使用した、LINE Botの作り方(入門バージョン)が、下記の記事で公開されています。

今回は、こちらをAWS SAMとTypeScriptでやってみました。

すいません、特にヒネリがあるわけではありません。LINEデベロッパーコンソールでの、チャンネル設定などは、全て上記の記事をご参照下さい。

2 TypeScript

TypeScriptは、/srcの下で.tsを編集し、/dstの下に出力するようにしました。

tsconfig.json

{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "sourceMap": true,
        "alwaysStrict": true,// use strict;
        "noUnusedLocals": true, // 未使用変数
        "noUnusedParameters": true,// 未使用引数
        "noImplicitAny": true, // 暗黙のAny
        "allowUnreachableCode": false,// 到達しないコード
        "allowUnusedLabels": false,// 到達しないラベル
        "strictNullChecks": true,// null チェック
        "noImplicitReturns": true,// 戻り値
        "outDir": "./dst", // 出力ディレクトリ
        "rootDir": "./src" // ソースディレクトリ
    }
}

そして、ボットのコードが下記のとおりです。

index.ts

import * as Lambda from 'aws-lambda';
import * as Line from "@line/bot-sdk";
import * as Types from "@line/bot-sdk/lib/types";

const accessToken = process.env.ACCESS_TOKEN!;
const channelSecret = process.env.CHANNEL_SECRET!;

const config: Line.ClientConfig = {
    channelAccessToken: accessToken,
    channelSecret: channelSecret,
};
const client = new Line.Client(config);

async function eventHandler(event:Line.WebhookEvent): Promise<any> {
    if (event.type !== 'message' || event.message.type !== 'text') {
        return null;
    }
    const message: Types.Message = { type: "text", text: event.message.text + "ってか😍" };
    return client.replyMessage(event.replyToken, message);
}

export const handler: Lambda.APIGatewayProxyHandler = async (proxyEevent:Lambda.APIGatewayEvent, _context) => {
    console.log(JSON.stringify(proxyEevent));

    // 署名確認
    const signature = proxyEevent.headers["X-Line-Signature"];
    if (!Line.validateSignature(proxyEevent.body!, channelSecret, signature)) {
        throw new Line.SignatureValidationFailed("signature validation failed", signature);
    }

    const body: Line.WebhookRequestBody = JSON.parse(proxyEevent.body!);
    await Promise
        .all(body.events.map( async event => eventHandler(event)))
        .catch( err => {
            console.error(err.Message);
            return {
                statusCode: 500,
                body: "Error"
            }
        })
    return {
        statusCode: 200,
        body: "OK"
    }
}

3 AWS SAM

使用したテンプレートは、以下のとおりです。ACCESS_TOKENCHANNEL_SECRETをLINE側のチャンネル設定からコピーするだけで、使い回せると思います。

template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: line-bot-sample
Globals:
  Function:
    Timeout: 3
    Environment:
      Variables:
        ACCESS_TOKEN: xxxxxx
        CHANNEL_SECRET: xxxxxxx

Resources:
  LINEBotSampleFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: dst/
      Handler: index.handler
      Runtime: nodejs10.x
      Events:
        LINEBotSample:
          Type: Api
          Properties:
            Path: /
            Method: post

Outputs:
  LINEBotSampleApi:
    Description: "API Gateway endpoint URL for Prod stage for LINE Bot Sample function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
  LINEBotSampleFunction:
    Description: "LINE Bot Sample Lambda Function ARN"
    Value: !GetAtt LINEBotSampleFunction.Arn
  LINEBotSampleFunctionIamRole:
    Description: "Implicit IAM Role created for LINE Bot Sample function"
    Value: !GetAtt LINEBotSampleFunctionRole.Arn

使用したバケットは、aws-sam-template-bucketとなってます。(これは、使いまわせません・・・)

$ aws s3 mb s3://aws-sam-template-bucket
$ sam package --output-template-file packaged.yaml --s3-bucket aws-sam-template-bucket
$ sam deploy --template-file packaged.yaml --stack-name line-bot-sample --capabilities CAPABILITY_IAM

デプロイが完了後、CloudFormationの出力から、LINEBotSampleApiの値をコピーして、LINE側のWebhook URLに設定します。

4 動作確認

動作している様子です。単純にオウム返ししているだけです。

5 最後に

今回は、Lambda+API GatewayによるLINEボットの超簡単なサンプルを試してみましちた。

LINEも色々な機能が満載です。このTypeScriptサンプルとTemplateを使いまわして、頑張って勉強してみたいと思います。