https://serverless-stack.com/ logo
#help
Title
# help
s

Sahan Amadoruge

11/03/2021, 5:37 PM
Sorry this isn't related to sst. I need to do a multipart file upload inside a Lambda function. Lambda is triggered by the S3 bucket on image upload. Need to get the uploaded image and then send it to another API service.Any suggestions?
r

Ross Coundon

11/03/2021, 5:38 PM
I ended up using busboy to extract the data
s

Sahan Amadoruge

11/04/2021, 11:20 AM
I don't really understand how it will help 😕
Copy code
var axios = require('axios');
var FormData = require('form-data');
var fs = require('fs');
var data = new FormData();
data.append('image', fs.createReadStream('/path/to/file'));
data.append('deviceInformation', '{"brand": "nokia"}');

var config = {
  method: 'post',
  url: '{API URL}',
  headers: { 
    'x-api-key': '{{apiKey}}', 
    ...data.getHeaders()
  },
  data : data
};

axios(config)
.then(function (response) {
  console.log(JSON.stringify(response.data));
})
.catch(function (error) {
  console.log(error);
});
I used this code to check my API locally
fs.createReadStream() returns a readableStream. So i used S3.getObject(params).createReadableStream()
But it's not working that way 😕
r

Ross Coundon

11/04/2021, 12:24 PM
Sorry, that doesn't help you, I'd mis-scan-read your msg on my phone
s

Sahan Amadoruge

11/04/2021, 12:25 PM
ok that's fine 🙂 thanks for trying to help 😉
r

Ross Coundon

11/04/2021, 12:28 PM
Well, thinking about it, if you're receiving an image in the API. You could use busboy to extract it. Then it's a separate case of uploading to S3. It may not be quite as performant as streaming but would likely be simpler. Another option would be to provide the client with a presigned URL for upload directly to S3
s

Sahan Amadoruge

11/04/2021, 12:29 PM
My lambda is triggered by S3. So image is coming from S3.
Copy code
S3.getObject({ Bucket, Key }, function (err, data) {
    if (err) {
      console.error(err.code, "-", err.message);
    }

    fs.writeFile(`/tmp/${fileName}`, data.Body, function (err) {
      if (err) console.log(err.code, "-", err.message);

      const data = new FormData();
      const readStream = fs.createReadStream(`/tmp/${fileName}`);
      data.append("image", readStream);
      data.append("deviceInformation", '{"brand": "samsung"}');

      const config: any = {
        method: "post",
        url: apiURL,
        headers: {
          ...data.getHeaders(),
        },
        data: data,
      };

      //       // console.log(config);
      console.log("Gonna send the api call 4", readStream);
      axios(config)
        .then(function (response) {
          console.log(JSON.stringify(response.data));
        })
        .catch(function (error) {
          console.log("Got error === ", error);
        });
    });
  });
Did this way. But there has to be a better way to do this 😕
r

Ross Coundon

11/04/2021, 12:44 PM
I think you could do something like
Copy code
const file = await S3.getObject({ Bucket, Key }).promise();
const formData = new FormData();
formData.append("image", file.Body);
const res = await <http://axios.post|axios.post>('<https://someUrl>', formData, {
  headers: formData.getHeaders()
});
s

Sahan Amadoruge

11/04/2021, 12:45 PM
thanks i'll try this
@Ross Coundon It worked. Since
file.Body
is a Buffer We need to pass a file name when appending it.
Copy code
formData.append("image", file.Body, { filename: fileName });
r

Ross Coundon

11/04/2021, 12:57 PM
excellent!