AWS Lambdaを使ってLINEBotを作ってみよう！

※この記事はAWSアカウントが作成済みであることを前提としています。
#はじめに
この記事は、2019/2/11に行なった[【学生大歓迎】プログラミング未経験者向け Node.js で LINE Bot 開発講座](https://linedevelopercommunity.connpass.com/event/119984/)参加者の一部より「botを永続化したい」という要望を受けたため、bot永続化のためのオンラインハンズオンを追加で行なった際に使用した資料です。（2/11のハンズオンの際はngrokを使用したため最長8時間しか動きませんでした。）
#AWS Lambdaとは
AWS (Amazon Web Service)のサービス（Faas）で、サーバレスでNode.jsやPython等を動かす事ができます。
#システム構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/370d242a-cb31-4fb4-53d6-473803817f51.png)
LINEサーバからのwebhookをAPI Gatewayで受け取り、それをLambdaの関数に渡す形になります。
#Botのチャネルを作ろう！
[こちらの記事](https://qiita.com/shinbunbun_/items/b1d82f5bd85786a7f06e)を参考にLINEBotのチャネルを作成して下さい。
#Lambdaの関数を作ろう！
- [AWSマネジメントコンソール](https://console.aws.amazon.com/console/home)にアクセスします。
<img width="1440" alt="スクリーンショット 2019-06-10 18.51.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9ce884a5-d90e-d690-42d3-5bde39ae9c25.png">
- メールアドレスとパスワードを入力してサインインします。
- サインインするとマネジメントコンソールが出てくるので、検索バーに「Lambda」と入力して「Lambda」を選択して下さい。
<img width="1440" alt="スクリーンショット 2019-06-10 18.54.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/abe4a7e6-729e-3364-3a05-d545507e4e70.png">
- Lambdaのコンソール画面が開くので右上にある「関数を作成」を押します
<img width="1440" alt="スクリーンショット 2019-06-10 18.54.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/c10f1d88-9cb9-27e0-ba5b-57c5620ed61d.png">
- 関数名、ランタイム、実行ロールを選択し、「関数を作成」を押します。（関数名は適当で結構です。また、既にロールがある方は新規作成しなくても結構です。）
<img width="1440" alt="スクリーンショット 2019-06-10 18.55.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/23888832-4c22-61f3-8a6a-844de4c2b05e.png">
- 関数作成完了です！
<img width="1440" alt="スクリーンショット 2019-06-10 18.57.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/1764d614-cffa-9250-616d-33db7db1041b.png">

#API Gatewayの設定をしよう！
##APIを作成しよう
- 左上の「AWS」を右クリックして新しいタブで開きます。
<img width="1440" alt="スクリーンショット 2019-06-19 20.51.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/7ef79766-a251-cbc0-9019-15f177320d3e.png">
- Api Gatewayを開きます。
<img width="1440" alt="スクリーンショット 2019-06-19 20.52.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/11b8a719-f65d-4426-2880-9bdaa086fdd6.png">
- 左上の「APIの作成」を押します。
※初めてAPIを作成する場合はこの画面が出てこない事があります
<img width="1440" alt="スクリーンショット 2019-06-19 20.53.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/21bcfe4e-b89b-6aff-7dac-03d30d7ca1d3.png">
- 適当に名前を入力したら右下の「APIの作成」を押して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 20.53.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9cd0c827-e013-7319-f1bf-c961040e3f64.png">
- 以上でAPIの作成は完了です！

##APIの設定をしよう！
- 「アクション」を押すとプルダウンメニューが出てくるので「メソッドの作成」を選択してください。
![uploading-0]()

- こいつをクリックします
<img width="1440" alt="スクリーンショット 2019-06-19 20.57.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/65d837bd-5a4b-a6f1-7373-e4f44b760148.png">
- POSTを選択して下さい
<img width="1440" alt="スクリーンショット 2019-06-19 20.57.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/e6821f46-2f57-e97f-2acc-283ff9478f03.png">
- チェックマークを押して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 20.58.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/4a9b64e3-cd73-c0a6-9fd8-b3f328f3a773.png">
- 「Lambda統合プロキシの利用」にチェックを入れて、「Lambda関数」に先程作成した関数の名前を入力してから「保存」を押して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 21.02.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/91e11ea6-7cc4-5c31-b2fe-9fa147ebf806.png">

- 「Lambdaに権限を追加する」というポップアップが出てくるので「OK」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/3fd3e2c6-5d76-8c8d-ead3-358a7deaafd6.png)
- これでPOSTリクエストを受け取ることが出来るようになりました！
- 次に「メソッドリクエスト」を選択して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 21.07.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/ab01c8de-1c32-968c-e8c8-a0aec2c06ae3.png">
- 「HTTP リクエストヘッダー」を選択して、「ヘッダーの追加」を押して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 21.08.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/13589d1f-abf3-fcfb-e304-1910a4ffe07c.png">
- ```X-Line-Signature``` と入力してチェックマークを押して下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 21.09.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9d757a31-440a-ee54-0aaa-adbdbaf8de1d.png">
- 「必須」にチェックマークを入れて下さい。
<img width="1440" alt="スクリーンショット 2019-06-19 21.10.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/ce7c09d2-50aa-a1c3-097a-a80af2ed7d03.png">
- 「アクション」を押すとプルダウンメニューが出てくるので、「APIのデプロイ」を押して下さい
<img width="1440" alt="スクリーンショット 2019-07-14 20.04.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/d8b1bdbc-a750-e7f8-5c52-62f0026ea5c1.png">
- 「デプロイされるステージ」の右にある四角いやつを押して、「新しいステージ」を選択して下さい<img width="1440" alt="スクリーンショット 2019-07-14 20.05.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/46b9792e-4372-b8b8-137c-82428145a62c.png">
- ステージ名を入力して下さい
※今回は「prod」にします
<img width="1440" alt="スクリーンショット 2019-07-14 20.33.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/ccce98a7-bdb7-c9eb-725c-8fce37f51912.png">
- 「デプロイ」を押して下さい<img width="1440" alt="スクリーンショット 2019-07-14 20.33.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/350254e4-a788-1786-c1ce-310b1f4fc8d4.png">
- これでAPIの作成は完了です！

※リクエストが本当にLINEから送られてきたものかを確認するために署名検証を行う必要があります。（検証しなくてもBotを動かすことは一応可能です。）
X-Line-Signatureには、その検証を行うための署名が記載されています。
X-Line-Signatureがリクエストヘッダーに含まれていないリクエストはLINEからのものではないため、受け取る必要がありません。なので、APIGateway側であらかじめ弾く設定にしています。
#Botのコードを書こう！
##Lambdaにコードをアップロードしよう！
※Lambdaはインラインエディタを使用してブラウザ上で直接コードを書くことが可能ですが、今回はモジュールが必要になるので纏めてzipでアップロードしていきます。

- いよいよBotのコードを書いていきます。[こちらのページ](https://github.com/shinbunbun/bot_lambda)を開いて「Clone or download」をクリックし、「Download ZIP」を選択して下さい。<img width="1440" alt="スクリーンショット 2019-06-19 21.41.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/45ed64cd-cbeb-496d-3f01-1f40ba7781f7.png">
- zipを解凍してください。
- 解凍して出てきたフォルダを開いて、中のファイルを纏めて圧縮します
<img width="769" alt="スクリーンショット 2019-07-14 19.42.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/543d7c81-c538-d354-7397-0f2444edfce3.png">
※zip形式でコードをLambdaにアップロードするには、関数名のフォルダ直下にindex.jsを置く必要があります（/関数名のフォルダ/index.jsという形）。ダウンロードしたzipをそのままアップロードしてしまうと以下の画像のように「/関数名のフォルダ/bot_lambda-master/index.js」となってしまうため、動作しません。
<img width="198" alt="スクリーンショット 2019-07-14 19.43.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/21f2f1a2-5fda-43ca-de63-4a65bc7ea953.png">
- 先ほど作ったLambda関数を開き、「コードをインラインで編集」というボタンを押してください
<img width="1440" alt="スクリーンショット 2019-07-14 19.37.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/56cb3b1e-5877-d1d0-615e-aec6b714f5db.png">
- 「.zipファイルをアップロード」を押してください
<img width="1440" alt="スクリーンショット 2019-07-14 19.37.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/0c0a3afd-77e7-2706-a799-234b8dbd223f.png">
- 「アップロード」を押してください<img width="1440" alt="スクリーンショット 2019-07-14 19.40.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/469e3360-49a0-f7dc-8ba4-4eef19ec6b9e.png">
- 先ほど圧縮したzipファイルを選択し、「開く」を押します<img width="1440" alt="スクリーンショット 2019-07-14 19.48.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/92255e1a-863e-3cb0-0504-0fa38b19abaf.png">
- 「保存」を押します<img width="1440" alt="スクリーンショット 2019-07-14 19.48.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/8b8ef8a4-83bb-3ba7-6057-5160d46241b2.png">
- 以下のような画面になれば成功です！
<img width="1440" alt="スクリーンショット 2019-07-14 19.48.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/2b1bfb87-e471-d5dc-2fe0-21f25144dcaf.png">

##環境変数にアクセストークンとチャンネルシークレットを入力しよう
※コードに直接アクセストークンを書くと精神衛生上良くないので、環境変数を使用します

- LINEDevelopersのBotのページを開き、アクセストークンの項目にある「再発行」を押して下さい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/20cacecc-eb42-d50b-3f87-5ef85ea0f8e7.png)
- 特に変更はせず、そのまま「再発行」を押します![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/13ad7df2-2810-4a40-089f-6bf813650b9d.png)
- 出てきた文字列をコピーします<img width="1440" alt="スクリーンショット 2019-07-14 19.55.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9a6a55a8-aacb-9169-46db-b660dbe8d60e.png">
- 先ほど作ったLambda関数を開き、下の方にある「環境変数」のキーに ```ACCESSTOKEN``` と入力して下さい<img width="1440" alt="スクリーンショット 2019-07-14 19.56.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/ae000e25-5e91-ec03-257f-37b1605f6e09.png">
- 「値」には先ほどコピーした文字列を貼り付けます<img width="1440" alt="スクリーンショット 2019-07-14 19.57.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/3a10462f-ea33-eb54-93d9-1363f53c94fe.png">
- Botのページを開き、Channel Secretをコピーします<img width="1440" alt="スクリーンショット 2019-07-15 13.31.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/73b07be9-1e87-92fa-4513-a3f678f80bf1.png">
- Lambdaの下の方にある「環境変数」のキーに ```CHANNELSECRET``` と入力して下さい<img width="1440" alt="スクリーンショット 2019-07-15 13.33.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/3af1661d-daa7-25e1-8843-a97fc3882fa5.png">
- 「値」には先程コピーした文字列を貼り付けます<img width="1440" alt="スクリーンショット 2019-07-15 13.33.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/346d8531-76da-234c-cd94-8d551db1c9ee.png">
- 右上の保存を押します
<img width="1440" alt="スクリーンショット 2019-07-14 19.57.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9f2b749f-0868-d9d7-e726-1d46a52febd0.png">

##Webhook送信をオンにしよう！

※LINEからの通知を先ほど作ったLambda関数が受け取れるように、Webhookの設定をしていきます。

- 先程作ったLambda関数を開いて下さい<img width="1440" alt="スクリーンショット 2019-07-14 21.08.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/825a6aaf-9bb6-a8f5-8ba5-ebbd90f12231.png">
- 「APIGateway」を押して下さい
※URLが表示されない方は一度ページをリロードしてみて下さい
<img width="1440" alt="スクリーンショット 2019-07-14 21.08.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/61a26b02-8d85-9524-676c-b0efa3ede477.png">
- 「APIエンドポイント」の隣にあるURLをコピーして下さい<img width="1440" alt="スクリーンショット 2019-07-14 21.09.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/de24a6c9-1929-5aa6-8040-d5096cc4c002.png">
- botのページを開いて、「Webhook URL」の項目にある「編集」ボタンを押して下さい<img width="1440" alt="スクリーンショット 2019-07-14 21.11.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9df510b1-8ea9-fc59-f020-296cd37bc4b9.png">
- 先程コピーしたURLを貼り付けて<b>　https://　を削除します</b>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/b18890e9-7cf0-9e62-e610-214a4a9dfa2b.png)
- 「更新」を押します![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/807406ea-63d6-11d9-f7df-95c3e42944d5.png)
- 「Webhook送信」の項目にある「編集」ボタンを押して下さい<img width="1440" alt="スクリーンショット 2019-07-14 21.12.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/deeea093-9a4e-f761-16ce-a9e8c6cd54d9.png">
- 「利用する」を選択して、「更新」を押します![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/9f6ada81-62ba-dd38-d4cc-746dbbfdb1e2.png)
- ページをリロードして、変更が反映されているか確認します

※たまに反映されていない場合があるので、その場合は再度設定変更を行なって下さい

- 以下のような状態になっていれば設定完了です！
<img width="1440" alt="スクリーンショット 2019-07-14 21.16.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/db93d07f-f151-22bd-db35-749ff7ca4634.png">
※apiのURLにモザイクをかけていませんが、当該APIは既に削除済みなので公開しても問題ないと判断し、そのまま掲載しています。モザイクあるとわかりにくくなるしね！

#作ったBotを試してみよう！
- botのページに友達追加用のQRコードが載っているので、そこからbotを友達追加します
<img width="1440" alt="スクリーンショット 2019-07-14 19.59.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260292/20d125fa-4b6e-97d4-60ee-952070ef6341.png">
- メッセージを送信して、送ったメッセージがそのまま返ってくれば成功です。

#おまけ
以下の資料の「おまけ」の手順で、「こんにちは」というメッセージが送られてきたら「Hello World」と返信して、「おはよう」と送られてきおたら「Good Morning!!」と返信するという事が出来ます。
https://qiita.com/shinbunbun_/items/b1d82f5bd85786a7f06e#%E3%81%8A%E3%81%BE%E3%81%91
また、以下の資料の「はじめに」〜「確認テンプレートを返信してみよう！」と同じ手順でテンプレートメッセージを返信することが出来ます。
https://qiita.com/shinbunbun_/items/81db9b7973553b2d665d

#前回ハンズオン参加者の方々へ
messageFuncは前回のハンズオンの際に使用したコードと全く同じになっています。