ハッカソン参加時の備忘録 ～ 第２回：【Python】１番お手軽なGUIであるLINEとAWS(Lambda)の連携をしてみよう ～

こんにちは。
ITエンジニアのきゅうと申します。

# 概要
さて、第２回は早速ちょっとしたアプリ開発を基に、ハッカソンで必要なIT技術に触れていきましょう。
ということで、今回はLINEのMessageAPIとAWSのLambdaを使った、オウム返しアプリを作っていきます。

何故これが最初なのか？
何度も言っておりますが、ハッカソンはとにかく時間がありません。
その中で動くものを作るとなると、UI（ユーザインタフェース）にかける時間は限りなく少なくしたい！！
だけど、UIを疎かにするとバック処理で凄いアプリを作ったとしても、見た目がショボい為、アプリ全体もショボい評価となってしまいます。

このジレンマを解消してくれる１つの手段が、LINE Bot（MessageAPI）になります。

LINE BotはLINE DeveloperとLINE Official Accountを登録することで、
簡単にLINEのMessageAPIを呼び出し、意図した処理を行って返答するBotアプリを作成することができるのです！！


# テクニカル
* Python3.11
* AWS lambda
* Line Message API


# 手順

## LINE Developersのコンソールより、プロバイダーを作成する。
### １．LINE Developersにアクセスする。

https://developers.line.biz/ja/


### ２．右上の『コンソール』をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/62823ac8-1628-1816-0263-0c6bd7bb085d.png)



### ３．ページの真ん中にある「作成」ボタンをクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/04619c06-d934-7883-184e-633d9a89e6c2.png)



### ４．ポップアップした『新規プロバイダー作成』画面の赤枠内に任意のプロバイダー名を入力する。
　その後、「作成」ボタンを押下する。
　※今回は「Test_Provider」と入力する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/3c4773b8-9611-dc3d-28fb-d54c5a9dcd12.png)



### 5.プロバイダーの作成に成功！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/0a94d45f-6c28-0ba1-70e6-9c7afbea1ce1.png)

作成したプロバイダーはまだ何もサービスが登録されていないので、
使用したいサービスを選択します。
選択できるサービスは以下になります。
* LINEログイン
* Messaing API
* ブロックチェーンサービス
* LINEミニアプリ

今回はその中の「Messaing API」を選択します。


## Messaging API（チャンネル）を設定する。

### １．先ほどの画面で、『Messaging API』を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/309cffe5-be8f-a2bf-c9e5-05b494eba8b5.png)


### ２．入力画面に遷移するので、必要な内容を入力する。
※今回は画面キャプチャーの取得の関係で、スマホの画面となっておりますが、大きな違いはありません。
※一応、入力例を載せさせていただきます。
![developers.line.biz_console_channel_new_provider=2001053284&type=messaging-api (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/4a6d0db5-ea2b-2667-0622-c39ab94fbd08.png)


### ３．「作成」ボタンを押下すると、『確認』画面が表示されますので、「OK」を押下。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/4175fead-ea28-38bb-5518-46b960af43cb.png)


### ４．その後の情報利用に関する同意書も『同意する』を押下する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/73380b47-52fa-3b4c-a8a5-51819949528b.png)


### ５．チャンネルが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/dac1d560-fe83-6ed0-b50c-d86832ffab9c.png)


## AWSのLambda関数を作成する。
### １．AWSのLambdaにアクセスし、「関数作成」ボタンを押下
さて、ここからはAWSにてLambda関数を作成していきます。
AWSにログインし、上部の検索テキストボックスで『Lambda』と入力し、Lambdaを開きましょう。
その後、「関数作成」ボタンを押下します。

### ２．関数の初期設定をします。
以下のように設定していきましょう。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/7c0afa81-ec14-b224-80d6-613b46735e36.png)

＜以下、注意ポイント＞
１．『ランタイム』については、タイミングによって表示内容がコロコロ変わります。
　　キャプチャー時は2023/12となりますので、最新のPythonとバージョンを選択しましょう。
２．『関数URLを有効化』にチェックを入れておきましょう。
　　また、認証タイプと呼ばれる選択肢が増えるので、『NONE』を選択しましょう。
その他はデフォルトでも構いません。適宜設定してくださいな。


### ３．関数の作成に成功。
関数の作成に成功すると、関数の一覧に命名した関数名が表示されます。
それをクリックすると以下のような画面が表示され、設定した通りの関数が作成されたことが分かります。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/f535a767-0e81-7f25-c572-0db671c65df4.png)


### ４．『lambda_function.py』の中身を修正する。
『lambda_function.py』の中身を以下のPythonソースで置き換えます。
```diff_python
- import json
- 
- def lambda_handler(event, context):
-     # TODO implement
-     return {
-         'statusCode': 200,
-         'body': json.dumps('Hello from Lambda!')
-     }

+ import logging
+ import os
+ import urllib.request
+ import json
+ 
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO)
+ 
+ def lambda_handler(event, context):
+     
+     logger.info(event)
+     
+     for message_event in json.loads(event["body"])["events"]:
+         
+         logger.info(json.dumps(message_event))
+         
+         url = "https://api.line.me/v2/bot/message/reply"
+         
+         headers = {
+             "Content-Type": "application/json",
+             'Authorization': 'Bearer ' + os.environ['ACCESSTOKEN']
+         }
+         
+         data = {
+             "replyToken": message_event["replyToken"],
+             "messages": [
+                 {
+                     "type": "text",
+                     "text": message_event["message"]["text"],
+                 }
+             ]
+         }
+         
+         req = urllib.request.Request(url=url, data=json.dumps(data).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!")
+     }

```
↓↓↓　コピー用　↓↓↓
```python
import logging
import os
import urllib.request
import json

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    
    logger.info(event)
    
    print("１．")
    print(event)
    for message_event in json.loads(event["body"])["events"]:
        print("２．")
        
        logger.info(json.dumps(message_event))
        
        url = "https://api.line.me/v2/bot/message/reply"
        print("３．")
        headers = {
            "Content-Type": "application/json",
            'Authorization': 'Bearer ' + os.environ['ACCESSTOKEN']
        }
        print("３．")

        data = {
            "replyToken": message_event["replyToken"],
            "messages": [
                {
                    "type": "text",
                    "text": message_event["message"]["text"],
                }
            ]
        }
        
        print("４．")
        req = urllib.request.Request(url=url, data=json.dumps(data).encode("utf-8"), method="POST", headers=headers)
        
        print("５．")
        with urllib.request.urlopen(req) as res:
            
            logger.info(res.read().decode("utf-8"))
            print("６．")
            return {
                "statusCode": 200,
                "body": json.dumps("Hello from Lambda!")
            }
    
    return {
        "statusCode": 200,
        "body": json.dumps("Hello from Lambda!")
    }



```

### ５．環境変数を設定する。
上記のソースコードの内、
```python
           'Authorization': 'Bearer ' + os.environ['ACCESSTOKEN']
```
の部分で環境変数を使用しておりますので、環境変数を設定します。
そもそもLINE DevelopersのAccessTokenはどちらで確認できるのか？

1. 『LINE Developers』にアクセス
2. 対象のプロバイダーを選択。
3. プロバイダー設定画面の以下で確認が可能です。
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/8ac832a3-088a-c27a-f7b3-b2de956a5a41.png)

4. AWSのLambdaに戻り、『設定』タブ⇒『環境変数』⇒『編集』ボタンをクリック
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/aa4ef653-5a04-8d84-df6a-f7284b1880e4.png)

5. キーに「ACCESSTOKEN」、値に【3.で確認したアクセストークン】を設定し、「保存」をクリック
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/77f1f450-85ce-719c-973a-93150ce93be8.png)


### ６．『AWS API Gateway』の設定
1. Lambda関数の上部のイメージ図より『トリガーを追加』をクリック
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/e826592a-c978-7dc5-b682-060339b17f29.png)
2. 「トリガーを追加」画面で以下のように設定します。
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/350913ab-d707-309a-6251-6d7245cf5101.png)
3. イメージ図の中に「API Gateway」が追加されるのでそれをクリック
4. 『API endpoint:』という項目があるので、その後のURLをコピーします。
5. LINE Developersの以下の場所にコピーしたエンドポイントを貼り付けます。
　　●（プロバイダーを選択）⇒「Message API設定」⇒『Webhook設定』

  
### ７．その他、エラーが出たときの設定
さて、以上で基本的な設定は終了です。
`●（プロバイダーを選択）⇒「Message API設定」⇒『QRコード』`
から、友達登録し、メッセージを送付してみましょう。

ここで、メッセージがオウム返しされなかったり、エラーが返ってきてしまう時があります。
そんな時は以下を試してみてください。
### ➀、「Webhookの利用」がONになっているか？
`●（プロバイダーを選択）⇒「Message API設定」⇒『Webhookの利用』`
について、『ON』になっている必要があります。
まずはそこを確認してみましょう！！
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/016fd585-299a-c7ef-7ea1-570ff1be54dc.png)

### ➁、『LINE official Account Manager』の自動応答メッセージの応答メッセージからステータスをオフにする
『LINE official Account Manager』にアクセスし、対象のアカウントを選択。
その後以下の画像の個所を確認し、『OFF（無効）』となっていることを確認しましょう。
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/b2d4959d-027e-3169-9234-c1ee13b91aae.png)

以上、いかがでしょうか？？
下記の画像のようにオウム返し出来ましたでしょうか？？
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3618971/4a725267-44db-3669-a00a-35c11377a53b.png)

簡単ですので、是非是非試してみてくださいね！！

次回は、Lambdaを外部接続させるためにNATゲートウェイを用意したいと思います。

ということで、本日はここまでです。
少しでも参考になったと思いましたら、「いいね」や「ストック」を押していただけますと、今後の励みになりますので、是非とも宜しくお願い致します。

最後までお読み頂きありがとうございました。