LINE Botに投稿した画像をLambdaで受けてS3に保存する


前置き

LINE Botに投稿した画像をS3に保存しようと思いぐぐったものの
『lambda 画像 s3』だと死ぬほどサムネとかリサイズとか系のが引っかかる。
ちゃうねん!LINE Botに投稿した画像を本当にそのまま単純にS3に保存したいだけやねん!その後の加工は別処理でしたいねん!
調べ方が悪いのかなかなかストライクな記事が見つからなかったので、とりあえずいろんな記事のやってる事を継ぎ接ぎした事のまとめ。
Lambdaはnode.js。

流れ

①LINE Botを使えるようにする
②LambdaでMessaging APIから投げられたリクエストを元に画像を取得する
③LambdaからS3へ画像を保存する

①LINE Botを使えるようにする

LINE Bot作成まではだいたい下記記事を参考にしてなんとかなったが、若干画面が変わってた。
といっても気合でなんとかなる範囲の変化だったので詳細は割愛。
LINE Messaging API と AWS Lambda で LINE BOT を作ってみた

②LambdaでMessaging APIから投げられたリクエストを元に画像を取得する

画像取得の記事は下記を参考。
LINE Bot作成周りとかリクエストの中身の説明とか細かく記載されているものの、Messaging APIの前身のLINE BOT APIに関しての内容なので、必要な部分だけを拝借。
とはいえかなり参考になった。
LINE BOT APIを使ってAWS Lambdaでサーバレスな版画風写真加工BOTを作る(Node.js)

LINEに投稿した画像は、別の場所に有効期限付きで保存された状態になっているらしい。
そのためLambdaから画像バイナリ取得用のAPIでデータを取ってくる必要あり。

var https = require('https');

// 引数のmessage_idは
// event_data.events[0].message.typeが"image"だった場合に
// event_data.events[0].message.idで取得したもの
var get_image = function(message_id,callback){

    // Request Headers
    var send_options = {
        host: 'api.line.me',
        path: '/v2/bot/message/'+message_id+'/content',
        headers: {
            "Content-type": "application/json; charset=UTF-8",
            "Authorization": " Bearer " + "{ MY_TOKEN }" // ←ここに自分のトークンを入れる(LINE Developersで発行したやつ)
        },
        method:'GET'
    };

    // APIリクエスト
    var req = https.request(send_options, function(res){
        var data = [];
        res.on('data', function(chunk){
          //image data dividing it in to multiple request
          data.push(new Buffer(chunk));
        }).on('error', function(err){
          console.log(err);
        }).on('end', function(){
          // ここに画像取得後の処理を書く
          // この場合は、引数で受け取った画像取得後の処理用callbackを実行
          // dataに画像のバイナリデータが入ってる
          callback(data);
        });
    });
    req.end();
};

③LambdaからS3へ画像を保存する

②で取得した画像データをS3へ保存。
LambdaでS3にデータを格納する

var AWS = require('aws-sdk');
AWS.config.region = 'ap-northeast-1';
var s3 = new AWS.S3({ apiVersion: '2006-03-01' });

// dataは画像のバイナリデータ
// ②の関数のcallbackがこれになるイメージ
var save_image = function(data){
    var params = {
        Bucket: 'my_bucket', // ←バケット名
        Key: 'test.png', // ←バケットに保存するファイル名
        Body: Buffer.concat(data)
    };
    s3.putObject(params, function(err, data) {
        // 画像保存後の処理
    });
};

終わりに

LINEに投稿した画像処理とかしたい、けどレスポンスは早くしたい、という事でいったん保存とその後の処理を分けたいというのが目的にあった。
今後はその画像処理部分で躓いたら記事書こうと思う。