Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return binary data from lambda function in AWS in Python?

I cannot get python lambda to return binary data. The node-template for thumbnail images works fine but I cannot get a python lambda to work. Below is the relevant lines from my lambda. The print("image_data " + image_64_encode) line prints a base64 encoded image to the logs.

def lambda_handler(event, context):     img_base64 = event.get('base64Image')     if img_base64 is None:         return respond(True, "No base64Image key")      img = base64.decodestring(img_base64)     name = uuid.uuid4()     path = '/tmp/{}.png'.format(name)      print("path " + path)      image_result = open(path, 'wb')     image_result.write(img)     image_result.close()      process_image(path)      image_processed_path = '/tmp/{}-processed.png'.format(name)     print("image_processed_path " + image_processed_path)     image_processed = open(image_processed_path, 'rb')     image_processed_data = image_processed.read()     image_processed.close()     image_64_encode = base64.encodestring(image_processed_data)      print("image_data " + image_64_encode)       return respond(False, image_64_encode)   def respond(err, res):     return {         'statusCode': '400' if err else '200',         'body': res,         'headers': {             'Content-Type': 'image/png',         },         'isBase64Encoded': 'true'     } 

Any pointers to what I'm doing wrong?

like image 246
Horv Avatar asked Jul 01 '17 11:07

Horv


People also ask

Can Lambda run binaries?

The Lambda execution environment is based on a specific Amazon Linux AMI and kernel version. Any native binaries that are used in a Lambda deployment package must be compiled in this environment, and only 64-bit binaries are supported.

How do I return AWS Lambda value?

Returning a valueIf you use the RequestResponse invocation type, such as Synchronous invocation, AWS Lambda returns the result of the Python function call to the client invoking the Lambda function (in the HTTP response to the invocation request, serialized into JSON).

Can a lambda function return a file?

You can't do that. Your file handle only has meaning in the context of your lambda function, it means nothing outside of it.


1 Answers

Following all the steps above didn't work on my case, because having the binary support for content-type = */* will convert all responses to binary.

My case:

  • Multiple lambda functions returning json (text), just a single lambda returning a binary file. All have lambda proxy enabled.

  • The lambdas are in an API Gateway

  • The API Gateway is behind CloudFront

Hint: I have notice an important information in the API Gateway -> Settings

Binary support description

Quoting:

API Gateway will look at the Content-Type and Accept HTTP headers to decide how to handle the body.

This means that the Content-Type response header must match Accept request header

Solution:

  1. Set Binary Media Types in API gateway to your mime type: image/jpg

  2. In your HTTP request set Accept: image/jpg

  3. In your HTTP response set Content-Type: image/jpg

{   "isBase64Encoded": True,   "statusCode": 200,   "headers": { "content-type": "image/jpg"},   "body":  base64.b64encode(content_bytes).decode("utf-8") } 
  1. Next we must tell CloudFront to accept the 'Accept' header from the request. So, in CloudFront distribution, click on your API Gateway instance (ID is clickable) and once redirected to CloudFront instance go to Behaviour tab, select the path-pattern of your API (example: /api/*) and click on Edit button.

Example of path patterns

On the new screen, you have to add Accept header to Whitelist.

whitelist Accept

Note 1: If you have multiple file types, you must add them all to Binary Media Types in the API gateway settings

Note 2: For those coming from serverless and want to set the binary types when deploying your lambdas, then check this post: setting binary media types for API gateway

plugins:   - serverless-apigw-binary  custom:   apigwBinary:     types: - 'image/jpeg' 

The serverless.yml file for cloudfront should contain:

resources:     WebAppCloudFrontDistribution:       Type: AWS::CloudFront::Distribution       Properties:         DistributionConfig:           ...           CacheBehaviors:             ...             -                #API calls               ...               ForwardedValues:                 ...                 Headers:                   - Authorization                   - Accept 
like image 179
C. Damoc Avatar answered Sep 28 '22 08:09

C. Damoc