AWS SAM Configuration for API Gateway Binary Response / Payloads

July 02, 2019  3 minute read  

Learn how to configure AWS SAM to enable Binary Response such as audio/wav, application/zip, image/jpeg, image/png etc from AWS Api Gateway with Lambda proxy integration.

Steps

In this walkthrough, I will use application/zip for example.

1. CloudFormation yaml

To enable Api Gateway Binary Response, you can set x-amazon-apigateway-binary-media-types in your API’s definition body.

MyApi:
  Type: AWS::Serverless::Api
  Properties:
    StageName: Prod
    DefinitionBody:
      swagger: '2.0'
      basePath: '/Prod'
      schemes: 
      - 'https'
      paths:
        /myMethod:
          post:
            produces:
            - "application/json"
            responses: {}
            x-amazon-apigateway-integration:
              uri: # api-gateway-arn using Fn::Join
              responses: {}
              passthroughBehavior: "when_no_match"
              httpMethod: "POST"
              contentHandling: "CONVERT_TO_TEXT"
              type: "aws_proxy"
      x-amazon-apigateway-binary-media-types:
      - "application/zip"

1.1 AWS SAM

Even though AWS SAM provide BinaryMediaTypes property but as of Aug 2019, there seems to be a bug that will removes the specified binary media type when you deploy updates for your API.

You can check out AWS SAM GitHub issues 553 and 566 for more information and update.

Thus, the following two syntax causes your specified binary media type to be removed in subsequent deployments.

Using Globals Api BinaryMediaTypes property:

Globals:
  Api:
    BinaryMediaTypes:
    - application~1zip

Using Single Api BinaryMediaTypes property:

MyApi:
  Type: AWS::Serverless::Api
  Properties:
    StageName: Prod
    BinaryMediaTypes: 
    - application~1zip
    ...

1.2 Binary Media Type */*

On the other hand, it works with a wild card binary type: *~1*. However, requests’ body object will be base64 encoded.

Setting Api BinaryMediaTypes as *~1* in yaml.

Globals:
  Api:
    BinaryMediaTypes:
    - *~1*

Note that you have to use ~1 instead of /. API Gateway will convert it to /. You can check AWS SAM 1.4.0 release log and AWS SAM API properties document for more information.

When BinaryMediaTypes is */*, you need to base64 decode event['body'] to read what it contains.

body = json.loads(base64.b64decode(event['body']))

2. Lambda Response

To pass binary response, you will need to base64 encode it and make it a UTF-8 string. In the response object, you have to include isBase64Encoded: true and Content-Type header with value as your payload mime type.

# your binary data is in data variable
byte_data = base64.b64encode(data)
rst_obj['body'] = str(byte_data,'utf-8')
rst_obj['headers']['Content-Type'] = 'application/zip'

Response JSON object

{
  "statusCode": 200,
  "isBase64Encoded": true,
  "body": "//NgxAAd...",
  "headers": {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "POST, GET, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type,X-Amz-Date,X-Api-Key,X-Amz-Security-Token",
    "Content-Type": "application/zip"
  }
}

Now, git push to deploy the changes.

3. Api Gateway Binary Media Type

After deployment, to verify addition of binary media type, open Api Gateway console and choose your API. Then, select Settings and make sure it has binary media type configured.

Api Gateway Binary Media Type

4. Http Requests

Your http requests need to include an Accept header with value as your binary media type. For example: Accept: application/zip.

The following is a http request example using AWS Amplify API object.

apiCall() {
  const apiName = 'apiName';
  const config = {
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/zip'
    },
    responseType: 'blob'
  };

  return API.post(apiName, '/myApi', config)
    .then(response => {
      return response;
    })
    .catch(err => {
      console.error('err: ', err);
    });
  });
}

5. Download Binary

To confirm whether your API returns binary response, it looks like this on Chrome DevTools.

Api Gateway Binary Media Type

To download your binary data, you can use browser built-in method saveAs.

this.apiCall()
  .then(res => {
    saveAs(res, 'myFiles.zip');
  });

Conclusion

Setting x-amazon-apigateway-binary-media-types property or SAM BinaryMediaTypes enables binary response from API Gateway.

Check out AWS Amplify API, Blob Response Type and Error Handling article to learn how to send requests for binary response on frontend using AWS Amplify.

Support Jun

Thank you for reading!    Support JunSupport Jun

Support Jun on Amazon US

Support Jun on Amazon Canada

If you are preparing for Software Engineer interviews, I suggest Elements of Programming Interviews in Java for algorithm practice. Good luck!

You can also support me by following me on Medium or Twitter.

Feel free to contact me if you have any questions.

Comments