AWS API Gateway base64Decode produces garbled binary?

rjmurt picture rjmurt · Jan 2, 2017 · Viewed 14.7k times · Source

I'm trying to return a 1px gif from an AWS API Gateway method.

Since binary data is now supported, I return an image/gif using the following 'Integration Response' mapping:

$util.base64Decode("R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")

However, when I look at this in Chrome, I see the following binary being returned:

enter image description here

Instead of:

enter image description here

Could anyone help me understand why this is garbled and the wrong length? Or what I could do to return the correct binary? Is there some other what I could always return this 1px gif without using the base64Decode function?

Many thanks in advance, this has being causing me a lot of pain!

EDIT

This one gets stranger. It looks like the issue is not with base64Decode, but with the general handling of binary. I added a Lambda backend (previously I was using Firehose) following this blog post and this Stack Overflow question. I set images as binaryMediaType as per this documentation page.

This has let me pass the following image/bmp pixel from Lambda through the Gateway API, and it works correctly:

exports.handler = function(event, context) {

  var imageHex = "\x42\x4d\x3c\x00\x00\x00\x00\x00\x00\x00\x36\x00\x00\x00\x28\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x18\x00\x00\x00\x00\x00\x06\x00\x00\x00\x27\x00\x00\x00\x27\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00";
  context.done(null, { "body":imageHex });

};

However the following images representing an image/png or a image/gif get garbled when passed through:

exports.handler = function(event, context) {

//var imageHex = "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x44\x00\x3b";
//var imageHex = "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b";
  var imageHex = "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3b\x0a"
  context.done(null, { "body":imageHex });

};

This seems to be the same issue as another Stack Overflow question, but I was hoping this would be fixed with the Gateway API binary support. Unfortunately image/bmp doesn't work for my use case as it can't be transparent...

In case it helps anyone, this has been a good tool for converting between base64 and hex.

Answer

M.R. picture M.R. · Dec 12, 2017

To anyone else having problems with this: I was also banging my head against the wall trying to retrieve a binary image over API Gateway proxy integration from lambda, but then I noticed that it says right there in the Binary Support section of Lambda Console:

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

So I added Accept: image/png to the request headers and it worked. Oh the joy, and joyness! No need to manually change content handling to CONVERT_TO_BINARY or muck about with the cli. Of course this rules out using, for example, <img src= directly (can't set headers).

So, in order to get a binary file over API Gateway from lambda with proxy integration:

  • List all supported binary content types in the lambda console (and deploy)
  • The request Accept header must include the Content-Type header returned from the lambda expression
  • The returned body must be base64 encoded
  • The result object must also have the isBase64Encoded property set to true

Code:

callback(null, {
    statusCode: 200,
    headers: { 'Content-Type': 'image/png' },
    body: buffer.toString('base64'),
    isBase64Encoded: true
}