LoginSignup
30
17

More than 3 years have passed since last update.

AWS API Gateway + Lambda から multipart/form-dataを用いてバイナリデータ(wav)をS3にputする

Last updated at Posted at 2019-04-29

やりたいこと

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を作成します。

image.png

Lambda関数を作成する

今回はpython3.6で作成してみました。
body-jsonにBase64でエンコードされたWAVファイルが送られていることを想定しています。
(よくあるサンプルですが・・・)

image.png

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を作成する

image.png

さらに統合リクエストの編集をします。

image.png

マッピングテンプレートを選択します。

image.png

マッピングテンプレートで
「テンプレートが定義されていない場合 (推奨) 」を選択し、
Content-Typeに
multipart/form-data
を追加して、
テンプレートの生成を行います。
テンプレートは「メソッドリクエストのパススルー」はデフォルトのままです。

バイナリメディアタイプにも忘れずに
multipart/form-data
を追加しておきます。

image.png

この状態で、
APIをデプロイすれば完成です。

image.png

早速URLにて呼び出してみましょう。

https://*********.execute-api.ap-northeast-1.amazonaws.com/test/wav

POSTMANで実験

image.png

WAVファイルをform-dataからPOSTしてみるとWAVファイルがS3に
作成されてます。

image.png
aaa.wav

これで問題はありません。
と言いたいところですが、
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

30
17
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
30
17