Waeez
Waeez

Reputation: 339

How to send a file in array of object to express server?

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

Upvotes: 0

Views: 6570

Answers (3)

AndyS
AndyS

Reputation: 816

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')
})

})

Upvotes: 0

Santhosh S
Santhosh S

Reputation: 792

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);
    
});

Upvotes: 3

Max
Max

Reputation: 4739

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

Upvotes: 5

Related Questions