Node.js
AWS
lambda
linebot
LINEmessagingAPI

ゼロから始めるLINEBot(AWS×node.js) ①とりあえず動かす

この記事で分かること

  • 決まった時間に決まった文章を喋るとこまで
  • 自分がハマったポイント

この記事の対象者

  • いろいろと初心者(自分がそうなので)
  • MessagingAPIのような外部APIを使ったことがない
  • AWSもあんま詳しくない(アカウントは持ってるくらい)

流れ

第1回 とりあえず動かす (この記事)
1.LINE Developersの登録/設定
2.実装(Lambda/node.js)
3.定期実行の設定(CloudWatch)

第2回 オウム返しの実装
4.ドメイン取得,DNS設定,SSL証明書の設定(Route53/ACM/SNS/S3)
5.イベントの受け取り(APIGateWay)
6.ユーザへの返信(Lambda/node.js)

第3回 ユーザ情報、投稿画像の保存 (予定)
7.DBの連携

1. LINE Developersの登録/設定

以下から。
https://developers.line.me/ja/
プロバイダーを作成し、その中にChannelを作成します。
ここまでは公式の説明に沿って行けば大丈夫だと思います。

次に、デフォルトの設定を以下の画像の通りに設定します。
・アクセストークンはこの画面から再発行が可能ですが、最大24時間で切れてしまうので後々自動更新を実装します。 →これは再発行時に、古いトークンが切れる期限であって、ここで設定する長期アクセストークンは有効期限はもっと長かったです。短期アクセストークンでも30日間有効でした。
・WebHook URLは次回の記事で設定します。とりあえず空欄でOK
・その他の設定はキャプチャ通りに設定

スクリーンショット 2017-10-29 02.48.17.png

2. 実装(Lambda/node.js)

AWSにログインして、Lambda→関数の作成→一から作成

  • [名前]...好きな名前
  • [ロール]...[カスタムロールの作成]を選択。

IAM設定画面が開くので、以下のように設定

  • [IAMロール]...[新しいIAMロールの作成]
  • [ロール名]...好きな名前

スクリーンショット 2017-10-29 09.49.23.png

ポリシードキュメント(CloudWatchへの権限だけ付与。デフォルト設定)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}

[許可]を押してIAMロールを作ったら、そのロールを指定して、Lambda関数を作成。
Lambda関数が作成されたら、関数コードに以下をコピペ。

  • ランタイムはnode.js6.10で動作確認済みです。
  • jsファイル名がindex.jsだと思うので、ハンドラ名はindex.handlerとしてください。
index.js
var https = require('https');
exports.handler = (event, context, callback) => {

    var data = JSON.stringify({
       "to": process.env.USER_ID,//CHANNEL設定画面で確認
       "messages": [
         {
           "type": "text", 
           "text": "そろそろ寝ろ!!"
         }
       ]
    });
    opts = {
        hostname: 'api.line.me',
        path: '/v2/bot/message/push',
        headers: {
            "Content-type": "application/json; charset=UTF-8",
            "Content-Length": Buffer.byteLength(data),
            "Authorization": "Bearer " + process.env.CHANNEL_ACCESS_TOKEN//CHANNEL設定画面で確認
        },
        method: 'POST',
    };

    var req = https.request(opts, function(res) {
        res.on('data', function(res) {
            console.log(res.toString());
        }).on('error', function(e) {
            console.log('ERROR: ' + e.stack);
        });
    });
    req.write(data);
    req.end();
};

LINE側のCHANNEL設定画面から、Your UserIDとアクセストークンを確認して、環境変数に設定します。

  • USER_ID...Your UserID。グループIDや他の人のID取得方法は割愛。
  • CHANNEL_ACCESS_TOKEN...アクセストークン。

スクリーンショット 2017-10-29 10.34.18.png

ここで注意点。

ネットでググると似た記事が複数出てくるのですが、総じて動きませんでした。。
なんの仕様変更なのか、リクエストヘッダーへのContent-Lengthの指定が必須です。

そのため、body(ここではdataという変数)のバイト長を以下のように取得してヘッダーに含めました。
確か2016/10頃にChromeのバージョンアップでも同様のことがあって仕事で対応した気がします。。

プログラムからリクエストを送る場合は必ずContent-Lengthを付けましょう。
"Content-Length": Buffer.byteLength(data),

テスト実行をしてみると、無事LINE上でメッセージが飛んできました!

スクリーンショット 2017-10-29 10.30.03.png

lambda上は正常終了してるのに反応がない場合はcurlで確認すると良いでしょう。

curlコマンドでリクエスト投げるならこう
curl -X POST -H 'Content-Type:application/json' -H 'Authorization: Bearer [AccesToken]' -d '{  "to": "[User ID]", "messages":[{"type":"text","text":"curlコマンドから投稿"}]}' https://api.line.me/v2/bot/message/push

3.定期実行の設定(CloudWatch)

さて、僕は夜更かしなので24時なったら寝るように促してくれると嬉しいです。
CloudWatchにcronの設定をします。

※標準時で設定してくださいね。

スクリーンショット 2017-10-29 12.41.49.png

以上です。

上にも書きましたが、AccessTokenが切れると使えなくなってしまいます。
続きの記事で対応しますが、とりあえず動かすことができました。

次回は、ユーザの投稿をHookしてオウム返しする機能をつくります。

所感

  • 1年未満の記事ですら動かないものばかり。コピペプログラマの自分にはしんどい
  • ゼロから記事って、どこまでゼロから書くべきなのか悩む。