LINE Messaging API とAWSサービスを連携させてみる～位置情報をDynamoDBに保存する～

# 概要

GWももう終わりですね。。。GW中に一つでも投稿しようと思っていたので、以前からやりたいなぁと思っていた。
LINE Messaging APIから位置情報を送信してAWSのDynamoDBへの保存を試してみました。
ふとこの場所メモしておきたいなあと思ったときにいろいろな地図アプリはあるけど、便利な反面いまひとつ自由度がない気がしているので、純粋に位置情報の保存だけしてます。
今後はこの位置情報を使っていろんな地図表示ができたらなぁと思っています。

## できるようになること

* LINEのUIを使って位置情報が送信できる
* 送信した位置情報はLINE bot/AWS Lambda(Python)経由でAWSのDynamoDBに保存される
* AWSはDynamoDB/Lambda/API Gatewayを使えるようになる
* 位置情報だけでなくテキストなども送信/保存できる

## 参考書籍

[Amazon Web Services クラウドネイティブ・アプリケーション開発技法　一番大切な知識と技術が身につく](https://amzn.to/2JT9nNb "Amazon Web Services クラウドネイティブ・アプリケーション開発技法　一番大切な知識と技術が身につく")
<a target="_blank"  href="https://www.amazon.co.jp/gp/product/B01E8EQ264/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B01E8EQ264&linkCode=as2&tag=ranpage-22&linkId=bed89168e2877ebb7e415fa97d735cc5"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=B01E8EQ264&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL110_&tag=ranpage-22" ></a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=ranpage-22&l=am2&o=9&a=B01E8EQ264" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
AWSのシステムアーキテクトを中心を説明した本は多いですが、
アプリケーション作成をメインに記載されていた本はこの本くらいだったので購入
基本的なサービス説明からサンプルプログラム／サンプルアプリケーションが豊富なので役立ちました。

## およその作業時間

1時間

## 事前準備

LINEアカウントを作成しLINEのChannleを作ったり、AWSのサービスを使うためにAWSのアカウントを作成する必要があります。Google等で調べればすぐ出てくると思いますが、以下の記事も参考に。
大量データの送信／保存でなければ無料です。

* LINE Channel作成
　[LINE Messaging API を使ってLINEにメッセージ送信／メッセージ返信する](https://qiita.com/fkooo/items/d07a7b717e120e661093 "LINE Messaging API を使ってLINEにメッセージ送信／メッセージ返信する")

* AWSアカウント取得
　[AWS初心者がAWS 認定ソリューションアーキテクト – アソシエイト資格試験に合格した時の勉強法](https://qiita.com/fkooo/items/e5284a4ed3c3466ffd41 "AWS初心者がAWS 認定ソリューションアーキテクト – アソシエイト資格試験に合格した時の勉強法")

## 実施手順

１．DynamoDBテーブル作成
２．ロール作成
３．位置情報保存用Lambda関数作成
４．API Gateway公開
５．LINE Channle設定

以降、それぞれについて要点を記載します。
張り付けてある画面は一部のため適宜画面の表示内容に従って操作してください。

### １．DynamoDBテーブル作成

最初はDynamoDBにテーブルを作成します。
AWSのサービスからDynamoDBを選び、**テーブルの作成**をクリック


![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/ae25a6b4-7d49-bebe-5465-613a03845cc1.png)

テーブル名とプライマリキーが必須のため入力します。
今回は、**LINEData**、**timestamp**としています。
※timestampは、LINEから送られてくるデータでユニークそうなものを選びました。適宜変更してください。
あとはデフォルトのまま、**作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/ceac0ffd-a6a5-1345-1171-d6cf1227ff31.png)

### ２．ロール作成

次にLambda関数に設定するロールを作成します。
サービスから IAM > ロール 選び、**ロールの作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/90b9b9fa-acc0-a888-94da-289ae6084a89.png)

ロール名は任意の名称を入力
信頼されたエンティティの種類を選択では、**AWSサービスのLambda**を選択
ポリシーにはお試しのため**AmazonDynamoDBFullAccess**を選択
※正式運用時はベストプラクティスに従い最小権限を設定しましょう(^^;)


![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/455b0831-d8ba-862a-61c1-f88ac690f459.png)

### ３．位置情報保存用Lambda関数作成

いよいよLambda関数を作成します。
サービスからLambda選び、**関数の作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/a5d1accf-ab3b-dd36-af25-aaeb19809e89.png)

名前は任意の名称を入力
ランタイムは、**Python 3.6**を選択
ロールは先ほど作成済の既存ロールを選択
最後に**関数の作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/ba910be0-14ca-2a47-e6c6-68ebca05c522.png)

画面中央くらいにあるコードを書くところに以下のコードを記載
戻り値には入力をそのまま返却するように設定（特に意味はない(^^;)）
コードを書いたら右上のボタンで保存します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/d84fedb4-adc5-1c14-38dd-88b1d58e4492.png)

```python

import boto3, json
from datetime import datetime

print('Loading function')      # Functionのロードをログに出力
 
def lambda_handler(event, context):
    # 文字列へ変換
    jsonstr = json.dumps(event, indent=2)
    print("Received event: " + jsonstr)
    
    timestamp = event['events'][0]['timestamp']
    print("timestamp: " + str(timestamp))

    dynamoDB = boto3.resource("dynamodb")
    table = dynamoDB.Table("LINEData") # DynamoDBのテーブル名

    # DynamoDBへのPut処理実行
    table.put_item(
      Item = {
        "timestamp": str(timestamp), # Partition Keyのデータ
        "message": jsonstr
      }
    )

    return event

```

保存したら同じく右上の**テストイベントの設定**からコードのテストを実行

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/9477a1b6-c4a1-e2fa-02d6-49d3bbe9f934.png)

テストデータには以下のLINE Messaging APIの疑似送信データを設定

```json

{
  "events": [
    {
      "type": "message",
      "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA",
      "source": {
        "userId": "U4af4980629...",
        " type": "user"
      },
      "timestamp": 1462629479859,
      "message": {
        "type": "location",
        "id": "325708",
        "title": "位置情報",
        "address": "Unnamed Road",
        "latitude": 35.65910807942215,
        "longitude": 139.70372892916203
      }
    }
  ]
}

```

テストデータの詳細は、Messaging API APIリファレンスを参照
　[Messaging API APIリファレンス](https://developers.line.me/ja/docs/messaging-api/reference/ "Messaging API APIリファレンス")

送信時のイベントオブジェクトは以下
　[Webhookイベントオブジェクト](https://developers.line.me/ja/docs/messaging-api/reference/#anchor-eff5d13cad53e16173242bbc2f157655a9e8dbd8 "Webhookイベントオブジェクト")

位置情報はこの辺↓ですね
　[位置情報](https://developers.line.me/ja/docs/messaging-api/reference/#wh-location "位置情報")

テスト実行後以下のようなメッセージがでれば成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/56742670-54ab-edb2-8e41-cc49548a0b12.png)

### ４．API Gateway公開

サービスからAPI Gatewayを選び、**APIの作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/3b91bb90-fe32-6d08-92f1-baa145ac59cb.png)

API名に任意の名称を設定し、**APIの作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/6dd5ecb9-13e9-3c00-6a37-411dcbd37f72.png)

作成したAPIにリソース（アクセス時のURLにあたるもの）を追加します。
**アクション**から**リソースの作成**選択し、リソース名に任意の名称を設定し、**リソースの作成**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/6dad3835-547a-d688-2cd2-6bb5b5be7d73.png)

リソースが作成できたらリソースに対し、メソッドを設定します。
作成したリソースを選択した状態で、アクションから**メソッドの作成**をクリックすると
リソースの下にセレクトボックスが表示されるため**POST**を選択後、
すぐ横の保存（チェックボタンのようなもの）をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/c2177574-efc7-9602-f041-5c38005469c2.png)

メソッドが作成できたらメソッドに対するセットアップを行います。
作成したLambda関数を設定し、**保存**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/d566ece8-8498-c730-3611-e02142bec001.png)

保存できたらここでもテストを行いましょう。
**テスト**をクリックし、

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/97a323ea-6117-fc84-f731-2f58339379b8.png)

表示されたリクエスト本文に先ほどと同じLINE Messaging APIの疑似送信データを設定し、
**テスト**ボタンを押すとテストできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/e831c11e-c6fa-dd64-d6a1-9c82c4b0bdbb.png)

テストが成功したらいよいよデプロイ（公開）です。
アクションから**APIのデプロイ**をクリック
ステージ名に任意の名称を設定後、**デプロイ**をクリック

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/cc5a803c-9f81-ff31-7ca4-9c273b769d8b.png)

デプロイに成功すれば、画面左側のツリーから**ステージ**をクリック後、
該当のリソース／メソッドを選択すると呼び出し用のURLが表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/dce1205f-5a34-5ab9-e3fc-37b04a69e5e8.png)

試しにアドレスバーにそのまま張り付けると
　message:"Missing Authentication Token"
と、表示されます。わかりにくいですが、POSTメソッドだけの定義のためGETだとこのように返却されるようです(^^;)

### ５．LINE Channle設定

LINEからAPIにアクセスするため、LINEのChannleに公開されたURLを設定します。
**Webhook送信**を**利用する**に設定後URLを貼り付けます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/52b624de-a7d1-a384-43d8-20d2cfc02dc2.png)

画面下部に友達追加用のQRコードがあるのでそれで友達追加して位置情報を送ってみます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/94ff638f-cd6a-eefc-95cf-a24828bc004e.png)

LINEからメッセージを送信する度にDynamoDBのテーブルにレコードが登録されていれば成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/e977882a-75a1-69f6-af70-382a0ad6c186.png)

## まとめ

送信画面、DB構築に悩まず位置情報が保存できるアプリケーションが短時間で作れるのがすごい。
今後は、この位置情報をこまめに蓄積しいい感じに地図描写ができるアプリケーションを作りたいと思う。