4
votes

I am trying to migrate my Node.js application from Google Cloud Functions to Amazon Lambda. The application load docx file from Amazon S3, process it and return that docx file. However I got stuck on the process of file return. In Google Cloud Platform I could do this:

module.exports = function(customENV){ return function(req, res) {
    new AWS.S3().getObject({ Bucket: aws_bucket, Key: aws_file }, function(err, data) {
        if(!err) { 
            res.set('Access-Control-Allow-Origin', "*");
            res.set('Access-Control-Allow-Methods', 'GET, POST');
            res.set('Content-Disposition', `inline; filename="rename.docx"`);

            res.type('docx');
            res.status(200);

            res.end(data.Body, 'binary');
        }
    });
}};

In Amazon Lambda I replicated the solution like this:

exports.handler = function(event, context, callback) {
    new AWS.S3().getObject({ Bucket: aws_bucket, Key: aws_file }, function(err, data) {
        if(!err) {
            var response = {
                statusCode: 200,
                headers: {
                    'Access-Control-Allow-Origin': "*",
                    'Access-Control-Allow-Methods': 'GET, POST',
                    'Content-type' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                    'Content-Disposition': 'inline; filename="rename.docx"'
                },
                isBase64Encoded: true,
                body: data.Body,
            };
            
            callback(null, response);
        }
    });
};

As API Gateway I used LAMBDA_PROXY with ANY method. Models/responses/mappings are all at "default". However the only response I get is "Internal server error". In CloudWatch logs I also see "Execution failed due to configuration error: Unable to base64 decode the body".

I tried replicating various solutions and/or different configurations of API Gateway, however with no luck. Probably I just don't understand Amazon's API Gateway and therefore I don't know how to configure it properly.

Perhaps as log says it could be also data conversion, but I tried conversions like toString("base64"), also no success.

Any ideas what should I do to make this minimal solution working? Thank you!

1

1 Answers

6
votes

You solution should work if you change your response to:

        var response = {
            statusCode: 200,
            headers: {
                'Access-Control-Allow-Origin': "*",
                'Access-Control-Allow-Methods': 'GET, POST',
                'Content-type' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                'Content-Disposition': 'inline; filename="rename.docx"'
            },
            isBase64Encoded: true,
            body: Buffer.from(data.Body).toString('base64'),
        };

This should get over your Unable to base64 decode the body error (if it doesn't, can you please log the response object to confirm that your lambda is returning succesfully and the body is a base64 string).

However you'll also need to add the binary media type to your gateway deployment, or else when you make the request your response will be the base64 string and not binary. There's a few clicks involved (full documentation):

  • Under the selected API in the primary navigation panel, choose Settings.
  • In the Settings pane, choose Add Binary Media Type in the Binary Media Types section.
  • Type a required media type, for example, image/png, in the input text field. If needed, repeat this step to add more media types.