[Fixed] uploading multiple FormField objects containing image data arrays from angular to express

Issue

I am trying to upload two FormField objects along with form data to express.

The part im stuck at is using the multer library in express to extract this data from the request. I can access the form data but not the FormField objects.

in angular:

requestBooking(formFields, aPics:Array<File>,bPics:Array<File>): {
    const aaPics = new FormData();
    const bbPics = new FormData();

    aPics.forEach(image => {
      aaPics.append('aImgs', image);
    });
    referencePics.forEach(image => {
      bbPics.append('bImgs', image);
    })
    
    // aaPics.forEach((value,key) => {
    //   console.log(key + ' ' + value);
    // })

    const payload = {
      form: formFields,
      aImgs: aaPics,
      bImgs: bbPics
    }

    this.rApi.makePostRequest(
      this.serverUrl + this.uris.requestBooking,
      payload
      ).subscribe(
        res => {
          let response: apiResponse = {
            type: 'Post',
            origin: this.apiOrigins.requestBooking,
            isError: false,
            content: res
          } 
          this.bookingUpdateResponse$.next(response);
        }, err =>  {
          
          this.bookingUpdateResponse$.next(err)
        }
      )
  }

I have confirmed the FormField data is correctly appending to the FormField objects so i think its getting sent

in express:

routes/booking.js

const aUploads = multer();
const bUploads = multer();

const bookingRouter = express.Router();
bookingRouter.post('/request', aUploads.array('aImgs', 10), bUploads.array('bImgs',10), requestABooking);

controllers/bookings.js

export const requestABooking = async (req, res) => {
 
    const PATH = './uploads';
    const bookId = uuidv4();

    const guestInfo = req.body.form.fmgroup1;
    const tattooInfo = req.body.form.fmgroup2;
    const bodyImgs =  req.body.form.aImgs;
    const tatImgs = req.body.form.bImgs;

    //console.log( req.body);

    // bodyImgs.forEach((value,key) => {
    //    console.log(key + ' ' + value);
    // })
}

I am not able to see the FormField information at this point.

I am pretty sure im using multer wrong in the routes but this is not the first thing ive tried. Ideally id rather not add to the route this way but instead extract the info from the object in the body as i think the former would require me to write a specific path for the upload in the angular.

If there is a way to do this within the express controller that would be the best solution i think but if not a solution would be very welcome!

Solution

BLUF: add all of your information into a single formData object.

After struggling with this for days I finally found a satisfactory answer!

The Problem: i wanted to pass info like this:

parentObject:{
  formInfo:{json},
  imageArr1:{Array<File>},
  imageArr2:{Array<File>}
}

But to handle multipart form information i needed to use something like "multer" to handle the special data stuff involved with data buffers and other large file streaming content.

To use this you format it at the router level in the backend, which initially i did not want to do as this would make my process look something like this:

Client uploads form data -> server posts data returns key for object created -> client uploads image data w/ key for management -> server returns good response all is well. but if ever that failed there are a tooooon of error handling processes that need to be put in place so i realllllllly didnt want to break this up into a multiple service calling scenario.

But the simple solution looks like this:

Client

Object.keys(formFields).forEach(field => { formData.append(field, formFields[field])}. 
fileArrAA.forEach(image => { formData.append('aaImages', image)}
fileArrBB.forEach(image => { formData.append('aaImages', image)}

this.apiSvc.post(url, formData).subscribe....

Server

const multer = require('multer');
const upload = multer();

router.post('/postThing', upload.any(), endpoint);


const endpoint = async (req, res) => {

  req.files; // has all the File data types in it as an array
  req.body; // has all the form fields or any key/value pairs in it
}

observation: i tried passing a nested object into the formData object, but i wasnt able to extract it in the backend so i ended up passing all the fields in the top layer of the formData object. probably missing a package for parsing api data or something.

Hope no one else has to go through this learning curve!

Leave a Reply

(*) Required, Your email will not be published