Python
AWS
lambda

バイナリデータ(画像)をAPIGatewayとLambdaを組み合わせてS3にPUTする

はじめに

以前、SORACOM BeamでバイナリデータをAPIGateway経由でS3にアップロードするという記事を書いたのですが、今回はその記事の続編です。

別のアドカレでもLambdaの素晴らしさを少し語らせていただいたのですが(これ)、Lambdaはかなり便利だと思ってます!。私が今携わっている案件でも、常に十数台のLambdaが立ち上がって処理をしてくれています。

ある日の私

実際にその構成を使って画像を保存していたのですが、ある日
私「だいぶ溜まってきたしCLIでローカルにダウンロードしよっと」

aws s3 cp s3://bucketName/key ~/image

S3「Access deniedやで」
私「ファッ!?」
という一連の流れがあって、もしかしてこの構成間違ってる?ということに気がつきました。

なにがあった?

それまでの構成では、画像ファイルをバイナリのまま、APIGatewayにSORACOMBeamを通してRESTAPIでPOSTして、そのあとS3にPUTするようにしてました。
しかしそれでは、S3にPUTする際に必要なHeader情報が不足しているようでした。(それならそれでエラー吐いて欲しいものですが…)
果たして不足分のHeader情報を全て網羅できるのだろうか。いやできない。(反語)
※必要なHeader情報は公式ドキュメントを参照。

それじゃあどうする?

「便利なものは 使ってしまえ ホトトギス。」(字余り)

ということで、AWS-SDKでPUTすることにしました。SDKを利用すればHeader情報などをよしなに補ってくれますし、おすし。
そして、便利屋Lambdaさんの登場です。
APIGatewayから一度Lambdaにデータを渡して、LambdaからAWS-SDKを使ってPUTする。という流れです。

以前までの構成は前編を参照してください。

APIGatewayからLambdaを呼び出す

スクリーンショット 2017-12-15 9.36.33.png

設定中に「APIGatewayにLambdaをinvokeする権限渡すけどええか?」と聞かれるのでOKしてあげてください。

マッピングテンプレートの設定

Content-TypeごとにどのようなテンプレートでLambdaに渡すかを設定します。
「Method Request passthrough」を選択しておけば問題ないです。

スクリーンショット 2017-12-15 9.41.37.png

バイナリサポートの設定

バイナリデータを送信するときのContent-Typeを設定しておきます

スクリーンショット 2017-12-15 9.44.40.png

Lambdaの作成

ランタイムはpython2.7です。
先ほどのマッピングテンプレートの形でeventに渡されてきます。

import json
import boto3
import base64

def lambda_handler(event, context):
    print json.dumps(event)

    try:
        s3 = boto3.resource('s3')
        bucket = s3.Bucket('bucketName')

        # バイナリがBase64にエンコードされているので、ここでデコード
        imageBody = base64.b64decode(event['body-json'])

        # リクエストパスを組み合わせてKeyにする
        imagePath = event['params']['path']
        key = imagePath['key'] + '/' + imagePath['name']
        print key

        bucket.put_object(
            Body = imageBody,
            Key = key
        )
        print 'success!'

    except Exception as e:
        print 'Error!'
        print e

これでLambda経由でS3に画像が保存されます。
SDKを利用してるので、Header情報やmetaデータはよしなにしてくれてます。

さいごに

やっぱりLambdaは便利ですね。

ではまた!