5

I am trying to create a lambda function which accepts an image as multipart/form-data, do some processing on the image and upload it to s3 and also returns reponse to the client. But i am stuck at the very first part of uploading the image to aws lambda using API gateway. I tried to do this in NodeJS as shown below:

exports.handler = async (event, context, callback) => {
  var buf = Buffer.from(event.body.replace(/^data:image\/\w+;base64,/, ""),"base64");

  var data = {
    Bucket: "bucket-name", 
    Key: "abc.jpg", 
    Body: buf,
    ContentType: 'image/jpg',
    ACL: 'public-read'
  };
  data = await s3.upload(data).promise();
  return {
         statusCode: 200,
         body: JSON.stringify(buf),
     };

I am getting the following response in Postman by making POST request to the api:

{
    "ETag": "\"b0e5b18d38904f109e0aef0b29e132be\"",
    "Location": "https://bucket-name.s3.us-east-2.amazonaws.com/abc.jpg",
    "key": "abc.jpg",
    "Key": "abc.jpg",
    "Bucket": "bucket-name"
}

But when i try to view the uploaded image in my browser using public url in the returned in the above response, i am getting empty image.

Can somebody point me the mistake here or suggest some better approach. Thank you.

25
  • For debug purpose, can you log event in console and see if you are getting payload properly from API Gateway. Commented Dec 29, 2018 at 16:36
  • Yes, i am getting the required payload. Commented Dec 29, 2018 at 16:41
  • 1
    Most likely s3 upload was interrupted since you already returned response back to API Gateway and lambda execution was done. Check this question and answers. stackoverflow.com/q/31633912/5030709. Try moving context.done() into callback function of s3 upload and see if upload is success. Commented Dec 30, 2018 at 3:08
  • 1
    This is not a recommended pattern to upload files to S3 since API Gateway has a payload limit and it also increases cost. A better approach would be to use S3 Signed URLs to upload directly from Browser client. Commented Dec 31, 2018 at 4:54
  • @Ashan Thanks for the suggesting this aproach. But After uploading the file i would have to make another HTTP call to my lambda function, don't you think this will increase the processing time? I want to make my application work in real time. Commented Dec 31, 2018 at 5:17

1 Answer 1

6

As suggested by Ashan, you can go with best practice of uploading images via browser.

If the image size is not that large, here is working example of uploading image to S3 via ApiGateway/Lambda Proxy Integration.

Lambda Function Code -

exports.handler = (event, context, callback) => {
  let encodedImage = JSON.parse(event.body).user_avatar;
  let decodedImage = Buffer.from(encodedImage, 'base64');
  var filePath = "avatars/" + event.queryStringParameters.username + ".png"

  var params = {
    "Body": decodedImage,
    "Bucket": "bucketName",
    "Key": filePath,
    "ContentType " : "mime/png"
  };
  s3.upload(params, function (err, data) {
    if (err) {
      callback(err, null);
    } else {
      let response = {
        "statusCode": 200,
        "body": JSON.stringify(data),
        "isBase64Encoded": false
      };
      callback(null, response);
    }
  });
};

Serverless.yml

service: aws-api-lambda-s3-image-upload

frameworkVersion: ">=1.1.0 <2.0.0"

provider:
  name: aws
  runtime: nodejs8.10
  iamRoleStatements:
    -  Effect: "Allow"
       Action:
         - "s3:ListBucket"
       Resource: "arn:aws:s3:::bucketName"
    -  Effect: "Allow"
       Action:
         - "s3:PutObject"
       Resource: "arn:aws:s3:::bucketName/*"

functions:
  index:
    handler: handler.handler
    events:
      - http: POST handler

Json Payload Should be -

{
  "user_avatar" : "<<base64 encoded image>>"
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thank you Imran. This works for the base64 encoded image.
@flamelite I just updated the github issue. your code should work. with rest of the s3 upload function I gave. Let me know for any feedback there.
Imran - Would this work for files like text files, pdf files, CSV or etc. Usually files are not base64encoded?
@Yusuf I don't think it works for binary formatted data!!
if we convert files to base64 then ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.