Jaime S
Jaime S

Reputation: 1698

Working with multipart/form-data in Lambda

I've a lambda function that is invoked from AWS API Gateway.

The lambda is receiving an image as a multipart/form-data and then the lambda needs to add some extra headers and pass that image to another external service using multipart/form-data too.

Right now, my service is doing this:

'use strict'
const AWS = require('aws-sdk');
const https = require('https');
const request = require('request');

exports.handler = (event, context, callback) => {

const options = {
        method: 'POST',
        url: 'https://external-service/image-storage',
        port: 443,
        headers: {
            "Content-Type": "multipart/form-data"
        },
        formData: {
            username: "67a43djte5s4cb54mnasbds23",
            secret: "47938hjfsdhjfdfdfs",
            photo: \\ I want to put here the image received in the event
        }
    };

    request(options, function(err, res, body) {
        if (err) console.log(err);
        console.log(body);
    });
}

In the photo parameter I've tried to put event.body but it's not working, as the external service gives me an "invalid request" (I've tried the external service with postman and it's working properly).

So I think that the problem is on the lambda.

When I print in the console the content of the event.body this is the output:

2020-04-02T13:17:27.478Z    0c03qsrf-78a2-2356-b9b0-0fd76fb367712   INFO    ----------------------------027326659651005153655343
Content-Disposition: form-data; name="image"; filename="MyImage.jpg"
Content-Type: image/jpeg
����JFIF��C...

Do I need to make any additional transformation to the body?

Thanks,

Upvotes: 2

Views: 4476

Answers (1)

Jaime S
Jaime S

Reputation: 1698

Just in case that someone arrives here having the same question that I had yesterday, the best approach is to follow the recommendation from Michael Hausenblas (see his comment under my question) and use S3 and pre-signed urls.

However, due some limitations in my front-end I couldn't took that approach.

Finally I had to replace the API input from multipart/form-data content-type to application/json and send the image enconded in base64 in a JSON object from my frontend to my lambda. And then from the lambda build the multipart object for the external service:

'use strict'
const AWS = require('aws-sdk');
const request = require('request');

exports.handler = (event, context, callback) => {

    let json_body = JSON.parse(event.body)
    var base64image = json_body.image;
    base64image = base64image.replace('data:image/jpeg;base64,', '');


    request({
        url: 'https://external-service/image-storage',
        method: 'POST',
        formData: {
          'username': '67a43djte5s4cb54mnasbds23',
          'secret': '47938hjfsdhjfdfdfs',
          'image': {
            value: Buffer.from(base64image, 'base64'),
            options: {
              filename: 'photo1.jpg',
              contentType: 'image/jpeg'
            }
          }
        }
      }, function (err,resp,body){
        if(err){
            console.log("Error");
        }else{
            console.log("Response" + body);
        }
    });   
}

As I said, I would recommend to follow the pre-signed urls approach but I offer this alternative in case you also have limitations on your front-end.

Upvotes: 1

Related Questions