Help us understand the problem. What is going on with this article?

LINE Botの通知イベントをAWS DynamoDBに保存する

More than 1 year has passed since last update.

image.png

LINE APIでメッセージを送信するためには、送信先のグループIDや、お友達のユーザーIDが必要ですが、一般アカウントの場合は、IDを調べるAPIがありません(グループメンバーのユーザーIDを取得するには、認証済みアカウントまたはプレミアムアカウントが必要)。

その代わり、フォローや、グループ参加のタイミングでWebhookが飛んでくるので、通知されるイベントオブジェクトに含まれるIDを覚えておくことで取り回しができます。

LINE APIのWebhookイベントで人の出入りで発生するイベントです。

  • フォローイベント
  • フォロー解除イベント
  • 参加イベント
  • 退出イベント
  • メンバー参加イベント
  • メンバー退出イベント

参考: Messaging APIリファレンス - LINE Developers

IDをDB化しておけば良さそうなので、WebhookイベントのタイミングでDynamoDBに保存する方法を試してみます。

前準備

LINE Developerアカウントのセットアップ方法、AWS Lambdaの使用方法は前回の記事を参考にしてください。

まずは、Webhookでどんな構造のイベントオブジェクトが送られているかをみるために、イベントをまるごとDynamoDBに保存してみます。

DynamoDBのテーブルを作成する

AWS DynamoDBダッシュボードで「テーブルの作成」をクリックします。
image.png
設定例:

項目 設定値
テーブル名 LineEvent
プライマリキー id
その他 デフォルト

IAMでロールにDynamoDBのアクセス権を与える

AWSのIdentity and Access Management (IAM)ダッシュボードでLambdaのロールを開いて、インラインポリシーを追加します。
image.png

サービスに「DynamoDB」を指定し、とりあえずすべてのリソースを指定します。実際には対象のDynamoDBのARNを個別に指定したほうが良いと思います。
image.png

ポリシー名を設定し、ポリシーを作成します。
image.png

そうすると、Lambda関数のDesignerにDyanamoDBが表示されます。
image.png

Lambda関数からDynamoDBへ書き込む

DBの準備ができたので、LINE BotのWebhookイベントオブジェクトをまるごとDynamoDBに書き込んでみます。事前にスキーマ定義をしなくても、プライマリーキーさえあれば、あとは好きな項目を入れられます。

index.js
'use strict';
const AWS = require("aws-sdk");

// event handler
exports.handler = function handleEvent(event, context) {

  const docClient = new AWS.DynamoDB.DocumentClient();
  var params = {
    "TableName": "LineEvent",
    "Item": {
      "id": event.requestContext.requestId,
      "event": event,
      "body": JSON.parse(event.body),
    }
  };
  docClient.put(params, function (err, data) {
    if (err) {
      console.error('Unable to put item. Error JSON:', JSON.stringify(err, null, 2));
    } else {
      console.log('DeleteItem succeeded:', JSON.stringify(data, null, 2));
    }
  });
};

コードをLambda関数に保存したら、LINEアプリからbotをフォローしたり、メッセージを送信してみます。DynamoDBダッシュボードのテーブルの「項目」を表示すると、レコードが追加されていることがわかります。

image.png

ためしに、「follow」イベント開くと、各項目がツリーで表示されます。めっちゃ便利。
image.png

イベントに応じてテーブルを更新する

様子がわかったので、ユーザーDBとメッセージDBを作ってみます。

テーブルの作成

これまでと同様の手順で、DynamoDBダッシュボードで新規にテーブルを2つ作成します。

テーブル名 プライマリキー プライマリキーの属性
LineUser userId 文字列
LineMessage messageId 文字列

Lambda関数のコード

follow, unfollow, messageイベントに対応してDynamoDBのテーブルにレコードを追加・削除するサンプルコードです。

index.js
'use strict';
const line = require('@line/bot-sdk');
const AWS = require("aws-sdk");

// create LINE SDK config from env variables
const config = {
    channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
    channelSecret: process.env.CHANNEL_SECRET,
};

// event handler
exports.handler = function handleEvent(event, context) {
    const body = JSON.parse(event.body);
    const eventType = body.events[0].type;
    const userId = body.events[0].source.userId;
    const timestamp = body.events[0].timestamp;
    const replyToken = body.events[0].replyToken;

    const docClient = new AWS.DynamoDB.DocumentClient();

    let params = {};
    switch (eventType) {
        case "follow":
            params = {
                "TableName": "LineUser",
                "Item": {
                    "userId": userId,
                    "timestamp": timestamp
                }
            };
            docClient.put(params, function (err, data) {
                if (err) {
                    console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
                } else {
                    console.log("Added item:", JSON.stringify(data, null, 2));
                }
            });
            break;

        case "unfollow":
            params = {
                "TableName": "LineUser",
                "Key": {
                    "userId": userId
                }
            };
            docClient.delete(params, function (err, data) {
                if (err) {
                    console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
                } else {
                    console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
                }
            });
            break;

        case "message":
            const messageId = body.events[0].message.id;
            const messageType = body.events[0].message.type;
            const messageText = body.events[0].message.text;
            params = {
                "TableName": "LineMessage",
                "Item": {
                    "messageId": messageId,
                    "userId": userId,
                    "text": messageText,
                    "timestamp": timestamp
                }
            };
            docClient.put(params, function (err, data) {
                if (err) {
                    console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
                } else {
                    console.log("Added item:", JSON.stringify(data, null, 2));
                }

                // おうむ返し
                return lineEcho(context, messageType, messageText, replyToken);
            });
            break;
    }
};

function lineEcho(context, type, text, replyToken) {
    // ignore non-text-message event
    if (type != 'text' || replyToken == '00000000000000000000000000000000') {
        const lambdaResponse = {
            statusCode: 200,
            headers: { "X-Line-Status": "OK" },
            body: '{"result":"connect check"}'
        };
        return context.succeed(lambdaResponse);
    }

    // create a echoing text message
    const echo = { type: 'text', text: text };

    // create LINE SDK client
    const client = new line.Client(config);

    // use reply API
    return client.replyMessage(replyToken, echo);
}

さいごに

これでユーザーIDのDB化ができたので、LINE botアプリの取り回しが楽になると思います。
今後は、Android/iOSアプリからDynamoDBの内容を取り出すために、Web API化してみたいと思います。

参考

yuppejp
とりあえずやってみます
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away