2
1

More than 3 years have passed since last update.

Python AWS Lambda でmultipart/form-dataのファイルをS3にアップロードする

Posted at

Python AWS Lambda でmultipart/form-dataのファイルをS3にアップロードする

概要

AWSのLambda経由でmultipart/form-dataできたものを、S3にアップロードする。

小言

clientでそのままS3に送る実装や、Blob化してファイルを送信しているのはよく見るが、めんどくさいし通常のApiならmultipart/form-dataを利用する方が多く(多いと思ってる)、なんでClientがApiとLambdaで変更しないといけないか不思議に思ったため。

Dependent
Result

TL;DR

  1. multipart/form-dataできたものをcgi moduleを利用してFormに変更
  2. Form化したデータからresponseBodyのfield名でファイルを取得

0. app.pyは最初こんなイメージ

app.py
import json

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }

1. multipart/form-dataできたものをcgi moduleを利用してFormのデータに変更

app.py
import json
import cgi
import io 
import logging # これは個人的に入れているのでほっておいていい
import base64

def get_file_from_request_body(headers, body):
    fp = io.BytesIO(base64.b64decode(body)) # decode
    environ = {"REQUEST_METHOD": "POST"}
    headers = {
        "content-type": headers["Content-Type"],
        "content-length": headers["Content-Length"],
    }

    fs = cgi.FieldStorage(fp=fp, environ=environ, headers=headers) # FieldStorageを利用してForm Dataとして扱う

def lambda_handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }

2. Form化したデータからresponseBodyのfield名でファイルを取得

requestの形が以下のようになっていいる想定です。

request.ts
{
    "file": File
}
app.py
import json
import cgi
import io 
import logging # これは個人的に入れているのでほっておいていい
import base64

def get_file_from_request_body(headers, body):
    fp = io.BytesIO(base64.b64decode(body)) # decode
    environ = {"REQUEST_METHOD": "POST"}
    headers = {
        "content-type": headers["Content-Type"],
        "content-length": headers["Content-Length"],
    }

    fs = cgi.FieldStorage(fp=fp, environ=environ, headers=headers) # FieldStorageを利用してForm Dataとして扱う
    return [fs["file"], None]

def lambda_handler(event, context):
    ## ここから追記
    file_item, file_item_error = get_file_from_request_body(
        headers=event["headers"], body=event["body"]
    )
   ## ここまで追記
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "hello world",
        }),
    }

こんな感じで適当に対応しましたが、多分もっといい書き方がある気がする...

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1