How to receive a file with an Aws Lambda (python)

Viewed 6974

I'm trying to figure out how to receive a file sent by a browser through an API call in Python.

The web client is allowed to send any types of files (let's say .txt, .docx, .xlsx, ...). I don't know if I should use binary or not.

The idea was to save the file after on S3. Now I know it's possible to use js libraries like Aws Amplify and generate a temporary url but i'm not too interested in that solution.

Any help appreciated, I've searched extensively a solution in Python but i can't find anything actually working !

My API is private and i'm using serverless to deploy.

files_post:
  handler: post/post.post
  events:
    - http:
        path: files
        method: post
        cors: true
        authorizer: 
          name: authorizer
          arn: ${cf:lCognito.CognitoUserPoolMyUserPool}

EDIT

I have a half solution that works for text files but doesn't for PDF, XLSX, or images, if someone had i'd be super happy

from cgi import parse_header, parse_multipart
from io import BytesIO
import json


def post(event, context):


    print event['queryStringParameters']['filename']
    c_type, c_data = parse_header(event['headers']['content-type'])
    c_data['boundary'] = bytes(c_data['boundary']).encode("utf-8")

    body_file = BytesIO(bytes(event['body']).encode("utf-8"))
    form_data = parse_multipart(body_file, c_data)

    s3 = boto3.resource('s3')
    object = s3.Object('storage', event['queryStringParameters']['filename'])
    object.put(Body=form_data['upload'][0])
1 Answers

You are using API Gateway so your lambda event will map to something like this (from Amazon Docs):

{
    "resource": "Resource path",
    "path": "Path parameter",
    "httpMethod": "Incoming request's method name"
    "headers": {String containing incoming request headers}
    "multiValueHeaders": {List of strings containing incoming request headers}
    "queryStringParameters": {query string parameters }
    "multiValueQueryStringParameters": {List of query string parameters}
    "pathParameters":  {path parameters}
    "stageVariables": {Applicable stage variables}
    "requestContext": {Request context, including authorizer-returned key-value pairs}
    "body": "A JSON string of the request payload."
    "isBase64Encoded": "A boolean flag to indicate if the applicable request payload is Base64-encode"
}

You can pass the file as a base64 value in the body and decode it in your lambda function. Take the following Python snippet

def lambda_handler(event, context):
    data = json.loads(event['body'])
    # Let's say we user a regular <input type='file' name='uploaded_file'/>
    encoded_file = data['uploaded_file']
    decoded_file = base64.decodestring(encoded_file)
    # now save it to S3
Related