wind_kind
wind_kind

Reputation: 611

req.file is undefined for multiple file uploads

I've read through all the possible answers here but I'm not sure anymore what the problem could be because none of them works. I have one form that uploads a single image and it works as expected but on a different form where I try and upload multiple files and have form inputs, the req.file is always undefined and the image data ends up in the req.body. So somewhere I think maybe there is an issue where multer is not getting the file data...?

I read in a couple of places that body-parser is possibly not playing well with multer but I unfortunately need them both.

route

const destination = './public/uploads/posts';
const storage = multer.diskStorage({
  destination: destination,
  filename: (req, file, cb) => {
    cb(null, file.originalname);
  },
});
const upload = multer({storage}).array('images');

router.post('/posts', (req, res) => {

  upload(req, res, (err) => {
    if(err) {
      console.log('errors', err)
      res.json({success: false, error: err})
    } else {
      if(req.files === undefined) {
        console.log('error: Images returned undefined');
      } else {
        const { title, description, url, auth_name, auth_id } = req.body;

        if(!title || !description) {
          return res.json({
            success: false,
            error: 'All fields required',
            message: 'Title and description fields are required'
          });
        }

        // path we store in the db
        let imageLocation = [];
        const post = new Post();

        for (const file of req.files) {
          imageLocation.concat('/uploads/posts/' + file.filename)
        }

        post.title = title;
        post.description = description;
        post.url = url;
        post.author_name = auth_name;
        post.author = auth_id;
        post.images = imageLocation;
        post.save((err, post) => {
          if(err) {
            return res.json({ success: false, error: err, message: 'post failed' });
          } else {
            return res.json({ success: true, message: "added new post", post: post });
          }
        });
      }
    }
  });
});

post in react component

My images are set in state which I get from the DropZone package (I tested without DropZone as well with same results. I made sure the the input name is "images"

submitNewPost = () => {
    const { title, description, url, images } = this.state;
    const auth_id = this.props.author_id;
    const auth_name = this.props.author_name;

    const formdata = new FormData();
    formdata.append('title', title);
    formdata.append('description', description);
    formdata.append('url', url);
    formdata.append('author_name', auth_name);
    formdata.append('author', auth_id);
    formdata.append('images', images);

    fetch('/api/posts', {
      method: 'POST',
      body: formdata
    }).then(res => res.json())
      .then((res) => {
        if (!res.success) {
          this.setState({ message: res.message });
        } else {
          this.setState({ 
              title: '', 
              description: '', 
              url: '', 
              images: '', 
              message: res.message 
          });
          socket.emit('newPost', res.post);
        }
      });
  }

UPDATE

With some help on this thread I managed to upload the images using my existing route and postman. When I test the route using my form, I still get an empty req.file and no uploads.

I added express-multipart-file-parser to my setup and I figure that is what brought me one step closer to fixing this.

Server

This is what I added to my server.js

 import { fileParser } from 'express-multipart-file-parser';
 app.use(fileParser({
  rawBodyOptions: {
      limit: '15mb',  //file size limit
  },
  busboyOptions: {
      limits: {
         fields: 20   //Number text fields allowed 
      }
  },
 }));

Upvotes: 0

Views: 2292

Answers (4)

Peter Khalko
Peter Khalko

Reputation: 19

for this issue not getting req.file in controller after upload middleware, while testing in postman select multiple file in single propertyenter image description here and of course in front end append the files in a loop

doc.forEach(file=> {
  formdata.append('file', file);
}

Upvotes: 0

wind_kind
wind_kind

Reputation: 611

thanks for all the help. I managed to fix it. Turns out I was concatenating the FileList object to an array in my state so the structure was all wrong and at the server it just failed. My images upload perfectly now.

If I posted that part of my react component, I'm sure any of you would have picked up on that in a second, sorry. Did not occur to me that the problem was further up in my component.

THE PROBLEM

onFileLoad = (e) => {
  this.setState({
    images: this.state.images.concat(e.target.files)
  });
}

THE FIX

onFileLoad = (e) => {
  this.setState({
   images: e.target.files
  });
}

submitMediaPOst = () => {
  const imageArr = Array.from(images);
  imageArr.forEach(image => {
    formdata.append('images', image);
  });
...

Upvotes: 3

khushboo
khushboo

Reputation: 715

You are missing to pass value with array.

router.post('posts', upload.array('image', 10), function (req, res, next) {

})

Upvotes: 0

n1stre
n1stre

Reputation: 6086

To properly populate req.files you need to use formdata.append like this:

images.forEach(image => {
  formdata.append('images', image);
})

Upvotes: 5

Related Questions