Line Messaging API + PythonとLambdaを使って、オウム返しBotをつくるのまとめ

# LineでAPIがあることを知りまして
API（Application Programming Interface）とLambdaの挙動の勉強を兼ねてBOTを作成してみました

## 謝辞：このお二人の記事にとても助けられました
というかこの2つの記事をそのまま実行したので、
詳しくはこちらをご覧くださいませ

[AWS Lambda + Python + LINE Botで傘が必要か教えてもらう](https://qiita.com/taku-0728/items/c80bcf65aba318ac6db0)
[API GatewayとLambda(Python)でLINE BOT(Messaging API)開発 [前編]](https://qiita.com/w2or3w/items/1b80bfbae59fe19e2015)

非常にわかりやすく丁寧に書かれており、BOT作成の喜びと
わかりやすい記事を読んでいく快感が得られました

# 自分の知識不足により途方に暮れた〜ようやくできた話
まずはこちらを読み進めていき、なるほどな、と思いながら
オウム返しBOTまでの手順を踏んでいきました

[AWS Lambda + Python + LINE Botで傘が必要か教えてもらう](https://qiita.com/taku-0728/items/c80bcf65aba318ac6db0)
LINE Developersでチャンネル作成〜Lambda、APIGatewayのトリガー追加まで何事もなく行きました

## Botでオウム返しができなかった...
何が足りないんだろう（自分の知識と読解力なんですけど）と、
途方に暮れつつ、他の記事を見ていきました

そこでこの記事を見つけました
[API GatewayとLambda(Python)でLINE BOT(Messaging API)開発 [前編]](https://qiita.com/w2or3w/items/1b80bfbae59fe19e2015)
最初に自分が書き写した記述に一番近い内容でしたので、この記事を読み進めていきました

こちらはAPIGatewayをトリガーとして追加ではなく、新規作成しており、
こちらの作り方も、なるほどな、と思いながら
「こんにちは！」と自動で返してくれるBOT作成まで、無事作ることができました！
若干手こずった自分のチャンネルを自分のトークに追加する方法もこちらでわかりやすかったです

## 再度オウム返しBOTを作ってみる
「こんにちは！」と自動で返してくれはしましたが、自分の作りたかったのはオウム返しBOT

Lambda関数とAPIGatewayを一旦削除し、再度[こちら](https://qiita.com/taku-0728/items/c80bcf65aba318ac6db0)の手順に沿って構築していき、
お世話になった2つのコードを`ガッチャンコ`しながら、試行錯誤を開始しました

# ようやく出来上がったのがこちら！

```python:ほーら、ホカホカのコードができましたよー。さぁ、食べましょ食べましょ！「パ〜プ〜」あ！とうふ屋さんが来てる！とうふ買うのをすっかり忘れてた！お兄ちゃん、ちょっととうふ買ってきて！いやいや言わないで、すぐだから！ねっ！おつりはあげるから！ほら、はやくしないと！とうふ屋さん行っちゃうから！...ありがとう！さ、あらためて食べましょ食べましょ！
import json
import urllib.request

def lambda_handler(event, context):
    for message_event in json.loads(event['body'])['events']:
        url = 'https://api.line.me/v2/bot/message/reply'
        headers = {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + 'あなたの取得したチャンネルアクセストークン'
        }
        body = {
            'replyToken': json.loads(event['body'])['events'][0]['replyToken'],
            'messages': [
                {
                    "type": "text",
                    "text": message_event['message']['text'],
                }
            ]
        }
        req = urllib.request.Request(url, data=json.dumps(body).encode('utf-8'), method='POST', headers=headers)
        with urllib.request.urlopen(req) as res:
            logger.info(res.read().decode("utf-8"))
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }
```

![linesmapho.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/05f7e41f-d5b5-913f-647a-1727a5c78293.jpeg)

### 改行もできる
![kaigyo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/210783e4-2309-435b-7882-be72c6af7ae1.jpeg)

### 絵文字は(emoji)となる
![emoji.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/53d0de9d-8689-c4d5-8166-c2673e63bdc0.jpeg)

###[`かわいい絵文字ですね〜！これどこで売っているんでしょうか？？？ここです！！！[クリッククリック！！！]`](https://store.line.me/emojishop/product/5c74fbb3100cc3130bd1fb04/ja)

# どの部分を変えたのか
- `import urllib.request`　[基本的な認証、暗号化認証、リダイレクション、Cookie、その他の介在する複雑なアクセス環境において (大抵は HTTP で) URL を開くための関数とクラスを定義](https://docs.python.org/ja/3/library/urllib.request.html)　を追記しました 
- `event['replyToken']`　を　`json.loads(event['body'])['events'][0]['replyToken']`　[メッセージオブジェクト:送信するメッセージの内容を表すJSONオブジェクト](https://developers.line.biz/ja/reference/messaging-api/#message-objects)・[応答メッセージを送るには、Webhookイベントオブジェクトに含まれる応答トークンが必要](https://developers.line.biz/ja/reference/messaging-api/#send-reply-message)　と書き換えました

## `json.loads`と`event`について
- Lambdaに渡されるJSONメッセージは全て event に格納されています。
    - 基本`event['要素名'][配列の要素番号]`辞書型の”キー”を指定することで”値”を取得することができます。
    - また、配列になっている場合はその配列の"要素番号"を指定することで配列の要素を取得できます。

[【AWS】LambdaのJSON入力と仲良くする（Python版）](https://qiita.com/Yuki_BB3/items/7885e06f82bebfa8a3bb)
ありがとうございます

## [Webhookイベントオブジェクトの例](https://developers.line.biz/ja/reference/messaging-api/#webhook-event-objects)のような形になっているJSONをデコードして`events`の`0番目`の`replyToken`を取得したんですよね

- Lambdaではevent.bodyでリクエストボディを取得
    - デフォルトではこのbodyは文字列なので、Content-Type:application/jsonの場合も「JSON文字列」になります。
    - そのため、一度JSONをパースする

[API GatewayからLambdaを呼び出すときにevent.bodyをオブジェクトで受け取る](https://qiita.com/the_red/items/e5808f3ceda64bef73e4)
ありがとうございます

- JSONをパースするとは？
    - JSON（JavaScript Object Notation）は名前の通り、JavaScriptのオブジェクトの表記法をベースとしたデータ形式であるため、例えばブラウザ側からJavaScriptなどでサーバー側のJavaなどに渡される
    - JavaでJSONを受け取ろうとすると、当然、そんなデータの形（JSON）は理解できないってことになるため、Javaで処理できるようにJSONをパース（解析）することが必要

[JSON（JavaScript Object Notation）をパースするとは？　quicktypeというサービスがアツいらしい](https://ts0818.hatenablog.com/entry/2017/11/23/210010)
ありがとうございます

- そもそもAPIとは？
    - Application Programming Interface
    - ソフトウェアにAPIという外部とやりとりする窓口を作り、外部アプリとコミュニケーションや連携ができる状態にする

[今さら聞けないIT用語：やたらと耳にするけど「API」って何？](https://data.wingarc.com/what-is-api-16084#:~:text=%E3%80%8CAPI%E3%80%8D%E3%81%A8%E3%81%AF%E3%80%81%E3%80%8C,%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9%E3%80%8D%E3%81%A8%E3%81%84%E3%81%86%E6%84%8F%E5%91%B3%E3%81%A7%E3%81%99%E3%80%82)
ありがとうございます

# その他、調べて知ったこと一覧
- 応答トークンというもの（房総半島みたいな響き）があり、これはLine側が自動で割り振って送ってくれるもの（だと思う）
- 'Bearer 'のところの半角スペースっているのだろうか？と思ったら、いるものでした
- 記述をしたらデプロイボタンを押すのと、この時点でテストをしてエラーがでても、実際は動きました
![image (10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/2b4f8aec-3286-e07b-0b9c-c287c1492a12.png)
- APIのほかにSDKというもの（あるシステムに対応したソフトウェアを開発するために必要なプログラムや文書などをひとまとめにしたパッケージ）があり、Lineにも`LINE Messaging API SDK`というパッケージが用意されている
- Herokuといもの（アプリケーションの開発から実行、運用までのすべてをクラウドで完結できる PaaS（サービスとしてのプラットフォーム））があり、それを介して、LineBotを作ることもできる
- BotでLineスタンプを送る場合、[送信可能なラインスタンプ一覧](https://developers.line.biz/ja/docs/messaging-api/sticker-list/#sticker-definitions)こちらにがありました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528622/c9266d2f-c986-dc60-0990-2a79938db194.png)

###[`かわいい絵文字ですね〜！これどこで売っているんでしょうか？？？ここです！！！[クリッククリック！！！]`](https://store.line.me/emojishop/product/5c74fbb3100cc3130bd1fb04/ja)