画像などのバイナリデータをアップロードするREST APIを作ります。詳細はAmazon API Gateway 開発者ガイドのバイナリペイロードをサポートするという章を読むこと。バイナリの扱いにちょっと戸惑ったのでメモ。
前提
API Gateway
バイナリメディアタイプ
API Gatewayはデフォルトではテキストペイロード( UTF-8 でエンコードされた JSON)として扱うため、バイナリペイロードで扱う場合は、APIの設定
からバイナリメディアタイプ
を指定し、バイナリとして扱うContent-Typeを設定します。
今回はmp3をアップしたいのでaudio/mpegを指定
マッピングテンプレート
さっきの手順でバイナリペイロードとして扱うことにはなったんですが、そのままバックエンド(Lambda)までバイナリで渡せるのかなと思ったら、違ってた。
API Gatewayは、統合リクエスト
の本文マッピングテンプレート
の設定で、バックエンドへの渡し方を決められます。ここでContent-Type:audio/mpeg
についてパススルーすれば、Lambdaにバイナリで渡るのかなと試したのですが、エラー。
{"message": "Could not parse request body into json: Unexpected character (\'\/\' (code 47)): maybe a (non-standard) comment? (not recognized as one since Feature \'ALLOW_COMMENTS\' not enabled for parser)\n at [Source: (byte[])\"\/9j\/4AAQSkZJRgABAQEASABIAAD\/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT\/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT\/wAARCAEqASwDASIAAhEBAxEB\/8QAHQABAAEFAQEBAAAAAAAAAAAAAAgBAgYHCQUEA\/\/EAEgQAAEDAwMDAgMFBQQHBQkAAAEAAgMEBREGByEIEjETQSJRYQkUMnGBFSNCkaEWUrHBFyYzYnKCkiRz0eHxJTRTY4OUo7Lw\/8QAHQEBAAEFAQEBAAAAAAAAAAAAAAECAwQFBgcICf\/EAC8RAQABAwMCAwYGAwAAAAAAAAABAgMEBREhMUEGBxITQlFhcYEUFZGhscEiM+H\/2gAMAwEAAhEDEQA\/\"[truncated 17128 bytes]; line: 1, column: 2]"}
結局どうやってもAPI GatewayからLambdaへはJSONオブジェクトで渡ることになるので、テキストとして処理しないと駄目みたいです。というこで、統合リクエスト
のLambdaプロキシ統合の設定
にチェックをしれて、ややこしいマッピングテンプレートの設定は省略します。
Lambda
API Gatewayからはbodyがbase64エンコードされたいつものJSONオブジェクトが来るので、それをデコードして処理します。簡単にS3に置くようなプログラムを実装すると以下。
bucket = 'xxxx' s3 = boto3.resource('s3') def lambda_handler(event, context): print(event) if event['isBase64Encoded']: date = datetime.datetime.now().strftime('%Y%m%d-%H%M%S') key = date + '.mp3' print(key) decode = base64.b64decode(event['body']) obj = s3.Object(bucket,key) res = obj.put( Body=decode, ContentType='audio/mpeg' ) print(res) return { 'statusCode': 200, 'body': json.dumps( { 'message': 'uploaded.', 'file': key } ), 'isBase64Encoded': False } else: return { 'statusCode': 400, 'body': json.dumps( { 'message': 'not binary file' } ), 'isBase64Encoded': False }