0

I have an array of the object, each object contains some properties of type string and a file.

This is how my array looks like:

const args = [
    {
        name: 'presentation',
        price: 9.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    },
    {
        name: 'presentation2',
        price: 20.99,
        tags: 'invest, finance, business',
        file: File,
        thumbnail: File
    }
]

const headers = {
 headers: {
   Authorization: `Bearer ${token}`
 }
};

My goal is to send this whole array of the object to the Express Server. there I will save information to the Mongo and upload the file to S3. But Currently, I am unable to get the file stream on the server when I send this in a POST request, even the whole req.body is an empty object when I console.log it

axios.post(`${slidesRoute}/createSlides`, args, headers);

Alternatively, I tried to put everything into FormData. for example:

let formData = new FormData();
    selectedFiles.forEach((selectedFile, i) => {
        formData.append(`name_${i}`, selectedFile.name);
        formData.append(`price_${i}`, selectedFile.price);
        formData.append(`tags_${i}`, selectedFile.tags);
        formData.append(`file_${i}`, selectedFile.file);
        formData.append(`thumbnail_${i}`, selectedFile.thumbnail);
    });
axios.post(`${slidesRoute}/createSlides`, formData, headers);

Then In the backend. I am unable to catch these files using multer. Because the filenames in form data are being generated dynamically like

file_1, file_2 file_3,...

But multer expects the exact filename to be passed for example multer().array('file')

so in my second approach I am unable to catch files using Multer

2
  • could you please attach server-side code Commented Jan 4, 2020 at 7:01
  • 1
    You need to add your server-side handling logic or the question is not answerable! Commented Jan 6, 2020 at 8:41

3 Answers 3

5

You can't include file inside JSON. File is not JSON-serializable. Ideally you should have a separate endpoint to accept your files, send them with content-type: multipart/form-data, receive unique id for that file stored on the server, then send your JSON with ids instead of files.

As a chaper alternative you can Base64 encode your files into a string, insert this string in your request, and then decode it back on the receiving side

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer. I think storing Files in Base64 going to make the JSON very heavy. This will cause a performance Issues
I tried another alternative, But this becomes challenging when it comes to multer. Please see the updated question
3
+25

FormData key values are array by default in your code Just change

formData.append(`file_${i}`, selectedFile.file);

to

formData.append(`file`, selectedFile.file);

You should be able to receive the file array in server side using multer().array('file')

Sample below demonstrating FormData key values array behavior

const formData = new FormData();
formData.append('key1', 'value1');
formData.append('key1', 'value2');
formData.append('key2', 'value1');

formData.forEach(function(value, key){ 
    console.log(key, value);
    
});

Comments

0

I use FormData to send a number of files - and then on the node.js server I use Formidable.

I've pasted some partial code below that may help - sorry it's not a smaller sample.

Hope it helps

On the browser side I have:

let form_data = new FormData()
form_data.append('upload_data', file)
$.ajax({
  url: '/file/upload' + remote_path + '/' + filename,
  type: 'POST',
  data: form_data,
  processData: false,
  contentType: false,
  success: (res) => {
...

On the node.js side (apologies for the length..)I have:

const fs = require('fs')
const formidable = require('formidable')
const path = require('path')
...
app.post('/file/upload/*', (req, res) => {
let filename = req.params[0]
let media = path.basename(filename)
let folder = filename.substring(0, filename.length - media.length)
let form = new formidable.IncomingForm()
// form.encoding = 'utf-8'
form.multiples = true
form.uploadDir = path.join(media_folder, folder)
form.keepExtensions = true
form.parse(req, (err, fields, files) => {
  if (err) {
    fail(res, 'failed to upload')
  } else {
    success(res)
  }
})
form.on('fileBegin', (name, file) => {
  const [fileName, fileExt] = file.name.split('.')
  file.path = path.join(form.uploadDir, `${fileName}_${new Date().getTime()}.${fileExt}`)
})
form.on('file', (field, file) => {
  fs.rename(file.path, path.join(form.uploadDir, file.name), (err) => {
    if (!res.headersSent) { // Fix since first response is received
      fail(res, 'an error has occured with form upload' + err)
    }
  })
})
form.on('error', (err) => {
  fail(res, 'an error has occured with form upload' + err)
})
form.on('aborted', (err) => {
  fail(res, 'Upload cancelled by browser')
})

})

Comments

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.