decadence

個人のメモ帳

LINE Messaging API w/AWS Lambda, Amazon API Gateway, apex

API GatewayAWS Lambda で LINE Messaging API を使った Bot を作る

business.line.me

tl;dr

  • API Gateway で LINE からの webhook を受け取る
  • API Gateway から AWS Lambda を呼び出す
  • Lambda のコードや設定値は apex で管理すると楽

LINE Bot w/Node

基本的には、client からのメッセージを webhook で受けとり、 Messaging API 経由で返事をする。

Lambda で Node を使って webhook を受けとり、テキストメッセージにだけエコーする処理は以下の通り。API Gateway から event を受け取る事を想定している。API Gateway に向けて {status: ..., headers: ..., body: ...} のような形で返すと、各 field が http の response にマッピングされる。

'use strict';
const crypto = require('crypto');
const https = require('https');

const channelAccessToken = process.env.CHANNEL_ACCESS_TOKEN;
const channelSecret = process.env.CHANNEL_SECRET;

const isValidSignature = (headerSignature, body) => {
  const generatedSignature =
    crypto.createHmac('sha256', channelSecret)
          .update(body, 'utf8')
          .digest('base64');
  return headerSignature === generatedSignature;
};

const replyTextMessage = (replyToken, text) => {
  const body = {
    replyToken: replyToken,
    messages: [
      {type: 'text', text: text},
    ],
  }
  const options = {
    method: 'POST',
    hostname: 'api.line.me',
    path: '/v2/bot/message/reply',
    headers: {
      'Content-Type': 'application/json; charset=utf-8',
      'Authorization': 'Bearer ' + channelAccessToken,
    },
  };
  const req = https.request(options, (res) => console.log(res));
  req.write(JSON.stringify(body));
  req.end();
};

exports.handle = (event, context, callback) => {
  // console.log(event);
  const xLineSignature = event.headers['X-Line-Signature'];
  const body = event.body;

  if (!isValidSsignature(xLineSignature, body)) {
    callback(null, {
      statusCode: 400,
      headers: {},
      body: 'NG',
    });
    return;
  }

  JSON.parse(body).events.forEach((event) => {
    if (event.type == 'message' && event.message.type === 'text') {
      replyTextMessage(event.replyToken, event.message.text);
    } else {
      console.log('no implementation.')
    }
  });
  callback(null, {
    statusCode: 200,
    headers: {},
    body: 'OK',
  });
};

apex

Node の Library とか使いたいし、気軽に Lambda に deploy したいので apex を利用する。

GitHub - apex/apex: Build, deploy, and manage AWS Lambda functions with ease (with Go support!).

上記の Node のコードでは channelAccessTokenchannelSecret環境変数から取得している。apex init 後にコードを置いて、apex deploy -E env.json すると、環境変数が設定された上で Lambda にコードを deploy 出来る

{
    "CHANNEL_ACCESS_TOKEN": "...", 
    "CHANNEl_SECRET": "..."
}

apex を利用した場合、zipにまとめて Lambda に乗せてくれるため、npm/yarn で管理した library も簡単に利用することが出来る。

API Gateway

手で設定するなら Endpoint を作って、 apex で deploy された Lambda へ繋げるだけ。 後々このあたりは terraform で管理する。