やりたいこと
API GatewayとLambdaを使って、S3にWAVファイルをPUTする。
実現方法
API Gatewayはmultipart/form-dataを使用したPOST可能なので、
WAVファイルを
API Gateway -> Lambda -> S3
にてPUTする。
環境
AWS
API Gateway
Lambda
S3
手順
テスト用S3Bucketを作成する
テスト用のBucketを作成します。
Lambda関数を作成する
今回はpython3.6で作成してみました。
body-jsonにBase64でエンコードされたWAVファイルが送られていることを想定しています。
(よくあるサンプルですが・・・)
import json
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.resource('s3')
bucket = s3.Bucket('multipart-test-*****')
# バイナリがBase64にエンコードされているので、ここでデコード
wavBody = base64.b64decode(event['body-json'])
key = "aaa.wav"
bucket.put_object(
Body = wavBody,
Key = key
)
APIを作成する
さらに統合リクエストの編集をします。
マッピングテンプレートを選択します。
マッピングテンプレートで
「テンプレートが定義されていない場合 (推奨) 」を選択し、
Content-Typeに
multipart/form-data
を追加して、
テンプレートの生成を行います。
テンプレートは「メソッドリクエストのパススルー」はデフォルトのままです。
バイナリメディアタイプにも忘れずに
multipart/form-data
を追加しておきます。
この状態で、
APIをデプロイすれば完成です。
早速URLにて呼び出してみましょう。
https://*********.execute-api.ap-northeast-1.amazonaws.com/test/wav
POSTMANで実験
WAVファイルをform-dataからPOSTしてみるとWAVファイルがS3に
作成されてます。
これで問題はありません。
と言いたいところですが、
aaa.wavは正常に再生できません。
他のサンプルコードでは、問題なくできてたのに!
私がはまった個所ですが、
body-jsonにてlambdaに送られる情報にはもともとのWAVファイルの情報以外も付与されており、
このままdecodeしてもwavファイルの形式に問題が発生してしまいます。
送信されているbytes文字列をデコードして確認するとこんな感じでした。
b'----------------------------648504498822251077984882\r\nContent-Disposition: form-data; name="file"; filename="0340.wav"\r\nContent-Type: audio/wave\r\n\r\nRIFFDs\x00\x00WAVEfmt
~(wavdataが続く)~
\r\n----------------------------648504498822251077984882--\r\n'
ファイルParse用のパラメータや、content情報が付与されています。
WAVファイルのみを抽出したいので、Bytes文字列で
b'RIFF 以下の情報が必要です。
lambda側を編集して、
import json
import boto3
import base64
def lambda_handler(event, context):
s3 = boto3.resource('s3')
bucket = s3.Bucket('multipart-test-matsuo')
# バイナリがBase64にエンコードされているので、ここでデコード
wavBody = base64.b64decode(event['body-json'])
wavs = wavBody.split(b'\r\n')
key = "aaa.wav"
bucket.put_object(
Body = wavs[4],
Key = key
)
とします。
送信側のWAVファイルと同様のファイルがS3にPUTされ、
問題なく再生できました。
(ファイルのバイト数も同じでした)
2019/05/08 追記
wavファイルの中で、/r/nがあると、
分割されてしまうので、
boundaryを使用して、
分割された配列を結合するようにしました。
ファイル名をkeyにしてParamsに付与するようにして、
ファイル名をそのまま保存できるようにしました。
key = event['params']['querystring']['filename']
# Boundary文字列の使用
boundary = jsons[0].replace(b'-', b'')
wavBody = jsons[4]
for i in range(5, len(jsons)):
if jsons[i].find(boundary) != -1:
break
else:
wavBody = wavBody + b'\r\n' + jsons[i]
bucket.put_object(
Body = wavBody,
Key = key
)
## 参考
https://www.youtube.com/watch?v=BrYJlR0yRnw
https://dev.classmethod.jp/cloud/aws/sugano-013-api-gateway/
https://qiita.com/is_ryo/items/966f720227cab2fff7f9