cmk
cmk

Reputation: 61

Get object from S3 in AWS Lambda function and send to Api Gateway

I am trying to get a .jpg file from a bucket and send it back to api gateway. I believe I have the setup correct as I see stuff being logged. It grabs the file from s3 fine, and gm is the graphicsmagick library. Not sure if I am using it right though.

In the lambda function I do this (alot of the code comes from the aws example):

async.waterfall([
    function download(next) {
        console.log(srcKey);
        console.log(srcBucket);
        // Download the image from S3 into a buffer.
        s3.getObject({
                Bucket: srcBucket,
                Key: srcKey
            },
            next);
        },
    function transform(response, next) {
        console.log(response);
        next(null, 'image/jpeg', gm(response.Body).quality(85));

    },

    function sendData(contentType, data, next){
        console.log(contentType);
        console.log(data);
        imageBuffer = data.sourceBuffer;
        context.succeed(imageBuffer);
    }
    ]
);

The response header has content-length: 85948, which doesn't seem right because the original file is only 36kb. Anyone know what I'm doing wrong?

Upvotes: 6

Views: 12077

Answers (2)

lenaten
lenaten

Reputation: 5335

You can achieve Get Image <-> API Gateway <-> Lambda <-> S3 integration with ease.

In lambda, instead of json, return base64 string representation of image (buffer.toString('base64')), force API Gateway to convert the string to binary and add specific Content-Type (so you don't need to use their limited binary support that enforce you to send a specific Accept header).

In AWS console, go to API Gateway, then go to the relevant method and update the settings:

  • Integration Request

    • Uncheck: Use Lambda Proxy integration
  • Method response

    • Add Response -> HTTP Status: 200
    • Add Header: Content-Type
  • Integration Response -> Header Mapping -> Response header -> Content-Type

    • Mapping value: 'image/jpeg' (single quote matter)

From command line, run the command below to force convert string to binary. First, retrieve the rest-api-id and the resource-id from API Gateway. Then, run in CLI (replace rest-api-id and resource-id with your own):

aws apigateway put-integration-response --rest-api-id <rest-api-id> --resource-id <resource-id> --http-method GET --status-code 200 --content-handling CONVERT_TO_BINARY

Upvotes: 5

adamkonrad
adamkonrad

Reputation: 7122

You shouldn't use API Gateway to pass back binary content when you use it with Lambda. API Gateway with Lambda are setup to respond with XML/JSON data. Read more about why and how here.

Try changing your callback chain so it uploads the modified image back to S3. After successful upload, send back URI of the target object and redirect your client to it.

Upvotes: 2

Related Questions