AWS CDK "触ったことない" からLINEBotを作るまで(TypeScript)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">やったぁああああ！🎉🎉<br>typescript + AWSCDK で超簡単にLINEBot作れるようになったぜい！ だれか一緒に盛り上がろう() <a href="https://t.co/mZXQkXpP8d">pic.twitter.com/mZXQkXpP8d</a></p>&mdash; ようかん / now / 🏫 (@inoue2002) <a href="https://twitter.com/inoue2002/status/1272005219983872000?ref_src=twsrc%5Etfw">June 14, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#はじめに
↑のツイートの通りですが、初めてTypeScriptでAWS CDKを使い、無事LINEBotを作ることができたので、忘れないうちに何をしたのか、まとめておきます。今後もう少し詳しくなったら訂正とかも加えるかもしれないです。参考文献とかは信頼できると思うので、ぜひそちらもみてください。間違っているとことがあればコメントいただけると嬉しいです。
@ufoo68さんが来月にAWS CDKを使ったLINEBotをハンズオンされるみたいなので、そういったところに参加する&ハンズオン資料を見ると良いと思います。イベント概要は[こちら](https://linedevelopercommunity.connpass.com/event/178215/)

#AWS CDKとは
[公式サイト](https://aws.amazon.com/jp/cdk/)
**AWS CDK**とは、プログラミング言語を使って**AWSのクラウド環境をプロビジョニングする**ためのオープンソースのフレームワークである。
AWS CDKではソースコードから**[CloudFormation](https://aws.amazon.com/jp/cloudformation/)**を作成してリソースのクラウドへのデプロイを行う。[CDKがわかる記事](https://qiita.com/ufoo68/items/d06756b6e7bb97359074)

#要するに
AWSのコンソールでぽちぽち設定するやつをコマンドを叩くだけで構築できるという優秀なやつですね。
その代わりソースコード(CloudFormation)に色々と設定を書き込みます。
プロジェクトの構成ごとGit管理したりできるので色々と便利ですね。


#前提知識は？
LINEBotを作ったことがある。(チャネルトークンとチャネルシークレットを既に取得している人)
Node.jsの環境構築済み。
npm が使える。

CDKなどはこの記事で環境構築についても取り扱うのでターミナル操作ができたら十分かと思います。


#AWS CDK環境構築
ぼくは公式のCDKチュートリアルをみながらやりました。
[公式チュートリアル](https://cdkworkshop.com/)
本記事はこちらに添いながら、必要な項目をやっていきます。

#公式チュートリアル
##Topページ
<img width="1423" alt="スクリーンショット 2020-06-16 22.06.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/cdfd0481-e972-48a1-5cf0-a4efd9c915b5.png">
公式チュートリアルのページに行くとこんな感じの画面になります。最初のページには挨拶が書いてるので次のページに行きます。

##AWS CLIページ
<img width="1431" alt="スクリーンショット 2020-06-16 22.08.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/86c23bf7-50b6-cc05-a40a-a2393a1c39e8.png">
何枚かページを進めると、AWS CLIをインストールしろと言われます。
[Win版インストール](https://docs.aws.amazon.com/cli/latest/userguide/install-windows.html#install-msi-on-windows) / [Macとか版インストール](https://docs.aws.amazon.com/cli/latest/userguide/awscli-install-bundle.html#install-bundle-other)
AWS CLIがよくわからんときは[こちら](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)

##AWS Account Config 
<img width="1434" alt="スクリーンショット 2020-06-16 22.12.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/2e11fff9-b02b-650a-4389-6cdae69aacdc.png">
AWSアカウントを作成したことがない方はAWSアカウントの新規登録してログイン、いつも使っている人はそのままログインします。
<img width="1420" alt="スクリーンショット 2020-06-16 22.14.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/0eb21438-76f5-5857-2b59-de24b6c8793e.png">
ログインできたら検索欄に「IAM」と入力し、IAMのページに移動する。
<img width="1426" alt="スクリーンショット 2020-06-16 22.16.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/7e14778a-d8d0-db73-6aab-b702f3c158e0.png">
左の欄から「ユーザー」を選択し、上の青いボタン「ユーザーの追加」をクリックする。
<img width="1382" alt="スクリーンショット 2020-06-16 22.20.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/419a8b66-a022-614b-9663-b613190e1528.png">
IAMユーザーの名前と種類を選択する。
<img width="1383" alt="スクリーンショット 2020-06-16 22.29.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/6e639a13-ee08-4256-29b1-da53507462b9.png">

そのユーザーに与える権限を選択し、次のステップへ行く。
<img width="1354" alt="スクリーンショット 2020-06-16 22.27.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/021adca2-28e3-4371-c0fc-a5b8ab010485.png">
発行されるIDを2種類メモする。（シークレットアクセスキーは一度しか表示されません。）

##認証情報をCLIに設定
<img width="1096" alt="スクリーンショット 2020-06-16 22.31.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/e8256035-d507-778b-37cc-846c2a690f29.png">
ターミナルを開いて作業していきます。

```ターミナル
$ aws configure

AWS Access Key ID []: ****************  //先ほど発行したアクセスキーID
AWS Secret Access Key []: ****************  //先ほど発行したシークレットアクセスキー
Default region name []: ap-northeast-1
Default output format []: json

```

##Nodejsのインストール
<img width="1026" alt="スクリーンショット 2020-06-16 22.34.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/cfd0100a-2122-9b7e-c0d2-88269f1a4138.png">

```ターミナル
$ node --version 
```
ターミナルに↑のように打ち込んでバージョン情報が表示されれば問題ないです。無理な場合はNode.jsの環境構築をしましょう。

#エディターをインストール
<img width="1039" alt="スクリーンショット 2020-06-16 22.37.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/1b39ca3e-1d26-5df2-748f-63f98a6d342f.png">
まだ何も入れてないひとはVSCodeを入れましょう。

#CDKをインストール
<img width="1033" alt="スクリーンショット 2020-06-16 22.38.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/05911c7b-67a9-83d4-1119-0711cd38c6de.png">

```ターミナル
$ npm install -g aws-cdk
```
↑のコマンドを実行し、`aws-cdk`をインストールしましょう。
インストールが終わったら、

```ターミナル
$ cdk --version
```
バージョンを確認してみましょう。バージョン情報が表示されない場合は再度やり直してください。
これでCDKの環境構築は終了です。それではLINEBotを作っていきましょう。

#コーディング

ターミナルに以下のコマンドを順番に打ち込む

```

 $ cd deskTop

[deskTop] $ mkdir line-sample && cd line-sample &&  cdk init app --language=typescript
[line-sample]$ mkdir  src &&  cd src && mkdir lambda &&  cd lambda && touch index.ts
```

```src/lambda/index.ts
import * as Lambda from 'aws-lambda';
import * as Line from "@line/bot-sdk";
import * as Types from "@line/bot-sdk/lib/types";
import { WebhookEvent } from '@line/bot-sdk';

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: Types.MessageEvent):　Promise<any> {
    if (event.type !== 'message' || event.message.type !== 'text') {
        return null;
    }
    const message: Types.Message = { type: "text", text: "CDKから生まれたBotのテストだよ！" };
    return client.replyMessage(event.replyToken, message);
}

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

    // 署名確認
    const signature :any = 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 as Types.MessageEvent)))
        .catch( err => {
            console.error(err.Message);
            return {
                statusCode: 500,
                body: "Error"
            }
        })
    return {
        statusCode: 200,
        body: "OK"
    }
}
```
続けてターミナルで色々インストールします。

```
[line-sample]$ npm install @types/aws-lambda @line/bot-sdk @aws-cdk/aws-lambda @aws-cdk/aws-apigateway
```
Lambda用に色々モジュールをインストールします。 

```
[line-sample/src/lambda]$ npm init -y && npm install @line/bot-sdk aws-lambda
```


```lib/line-sample-stack.ts

import cdk = require('@aws-cdk/core');
import * as lambda  from '@aws-cdk/aws-lambda';
import * as apigateway from '@aws-cdk/aws-apigateway';

export class LineSampleStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const lineSampleLambda = new lambda.Function(this, 'LineSampleLambda', {
      code: lambda.Code.asset('src/lambda'),
      handler: 'index.handler',
      runtime: lambda.Runtime.NODEJS_10_X,
      timeout: cdk.Duration.seconds(5),
      environment: {
          ACCESS_TOKEN: "xxxxx",
          CHANNEL_SECRET: "xxxxx"
      }
    });

    const api = new apigateway.RestApi(this, 'LineSampleApi', {
        restApiName: 'line-sample'
    });
    const lambdaIntegration = new apigateway.LambdaIntegration(
      lineSampleLambda, { proxy: true } );
    api.root.addMethod('POST', lambdaIntegration)
  }
}
```

LINEBotのチャネルシークレットとアクセストークンを入力しないといけないのでお忘れなく。


```testconfig.json
"lib": ["es2018","dom"]
```

ここからはターミナル操作です

```
$ npm run build  //ビルドする

$ cdk deploy 
```
成功すればたったこれだけでAPIGatewayの設定などを勝手にやってくれて、Lambdaにデプロイすることができます。
実際にAWSコンソールからAPIGateayのページを見にいきましょう。

<img width="1434" alt="スクリーンショット 2020-06-16 23.00.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488939/6b715924-5fc2-4e09-0fa7-40e7af47b9a4.png">
このようにAPIのURLが発行されています。あとはこれをコピーしてLINEBotのWebhookURLに設定するとAWSCDKでLINEBot構築完了です。

お疲れ様でした！🎉🎉🎉

多少省略した部分もありますが、参考文献には細かく書いてあるのでぜひそちらも参照ください。

#参考文献
[LINEアプリのサンプルをCDKで書き直して見て、その凄さを実感しました](https://dev.classmethod.jp/articles/aws-cdk-line-sample/)

#おわりに
AWS CDKはまだまだアップデートしまくりの機能ですが、使えるようになると色々と幸せになれるので皆さんもぜひお試しあれ！