Brian
Brian

Reputation: 395

Why can't I access req.body with multer?

My app (using vue) allows users to upload files with some info about the data to my node backend. When the user submits the form, this function is triggered:

methods: {
      buttonOK () {
        const formData = new FormData()

        formData.append('name', this.detailFirm.name)
        formData.append('description', this.detailFirm.description)
        formData.append('version', this.detailFirm.version)
        formData.append('date', this.detailFirm.date)
        formData.append('file', this.file)

        for (var [key, value] of formData.entries()) {
          console.log(key, value)
        }

        let headers = {
          'Content-Type': 'multipart/form-data',
          'Accept': 'multipart/form-data'
        }

        this.$http.put('/firmware', formData, {headers: headers})
        this.visible = false
      }

The log statement shows everything that it ought to, and when this request is made, the network tab in the chrome dev tools shows the post data going through, and it has all the values it should:

name: test
description: test
version: 1
date: 0555-05-05
file: (binary)

My multer middleware looks like this:

const multer = require('multer')
const mult = multer({
  dest: '/firmware'
})

module.exports = function (req, res, next) {
  /* --Convert multipart/form-data to useable format within express-- */
  if (req.path === '/firmware') {
    mult.single('file')
    console.log('MULTER MIDDLEWARE')
  }
  next()
}

The log statement there works, leading me to believe that multer is working.
I can't seem to access this information in back end though. Here I have tried both file and formData as the file name in mult.single('').

Here is my controller function:

let firmware = {
    name: req.body.name,
    version: req.body.version,
    description: req.body.description,
    date: req.body.date,
    file: req.body.file
  }
  firmwareRepo.create(firmware, (err, create) => {
                   .............

I've read some other questions, and have made a few adjustments, but I always get an empty object when I log req.body in the controller. Please advise.

Upvotes: 2

Views: 4514

Answers (4)

Sahil Gupta
Sahil Gupta

Reputation: 78

My scenario and how i fixed it is by appending the needed key at first in the files array:

Working on ecommerce website, my product files were uploaded first and then product was getting created. It means, i dont have product ID on the time of uploading files and i needed it to make the proper path.

In my uploadFileHandler function, i have populated the files in formdata, then later when doing actual upload to Amazon S3 using multer at the time of submit, i have appended the ProductID key first into the form data like below, Note that tempFiles are simply those files, which i got from "upload files" button (array):

        // Create a new FormData object
        const formData = new FormData();
        formData.append('productId', productId); // Append productId first

        // Append existing entries from tempFiles
        tempFiles.forEach((value, key) => {
            formData.append(key, value);
        });

By this i was able to append the ProductID before the Files and the later send the request like below:

        const { data } = await axios.post(
            '/api/upload/product',
            formData,
            config
        );

Upvotes: 0

Brian
Brian

Reputation: 395

I don't know why this worked, but everything started functioning as it should when I stopped using multer as an imported middleware, like this:

module.exports = function (req, res, next) {
  /* --Convert multipart/form-data to useable format within express-- */
  if (req.path === '/firmware') {
    mult.single('formData')
    console.log('MULTER MIDDLEWARE')
  }
  next()
}

and instead applied it directly to the route function, like this:

router.put('/firmware', upload.single('formData'), firmware.create) // doesn't work as standalone middleware

If anyone knows why that would be the case, please let me know.

Upvotes: 0

ldruskis
ldruskis

Reputation: 799

EDIT:

Firstly, I remember I had one problem on the frontend (React), by adding headers, which are not needed (somehow by adding formdata headers u **** up everything), here is the example:

data append stuff goes here 

const data = new FormData()

data.append('id', values.id)

......

return async (dispatch) => {
                const respond = await fetch('/api/postdata', {
                method: 'post',
                headers: {
                   //SEE? THIS IS EMPTY
                },
                body: data
            })

            // send form to backend
            dispatch(dataSend())
        }
    }

Second issue could be on the backend. The thing is, that you can't just simply access file info through the req.body. You need to access it through the req.file

  .post('/api/post', (req, res, next)=> {
    const photo = {}
    const newData = {}

    uploadData(req, res, (err) => {
      if(err){
        console.log('error')
      }
      else {
        Object.assign(photo, {file: req.file})
        Object.assign(newData, {newData: req.body})

Then pass the photo to where you want to do something with it

    const addDataController = new AddDataController(req, res, next, newAdvertData, photo)
    addAdvertController.postAdvert()
  }
})

Basically what I did is I separated regular data with file, and passed them further to combine and conclude the form. Sorry if this won't help, you're very close anyways!

Upvotes: 1

IDIR Samir
IDIR Samir

Reputation: 31

https://github.com/expressjs/multer#diskstorage

Note that req.body might not have been fully populated yet. It depends on the order that the client transmits fields and files to the server.

Upvotes: 3

Related Questions