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
- multipart/form-dataできたものをcgi moduleを利用してFormに変更
- 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",
}),
}
こんな感じで適当に対応しましたが、多分もっといい書き方がある気がする...