Title: I cannot upload files to the directory I specified using node js multer
Tags: javascript;node.js;json;reactjs;mongodb
Question: I created a web service using node js. I created a form with React interface and added user information and file upload. I save this information to mongodb. I want to save the file to the node js server using multer but did not add files to the directory I specified. What do I need to fix?
Routes
const express = require('express')
const User = require('../models/index')
const router = express.Router()
const multer = require('multer')
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, './public/uploads');
},
filename: function (req, file, cb) {
cb(null , file.originalname);
const upload = multer({ storage: storage })
/* create new*/
router.post('/', upload.single('image'), (req,res)=&gt;{
user = new User({
name:req.body.name,
email:req.body.email,
password:req.body.password,
img: req.file
});
user.save(()=&gt;{
res.json(user)
})
/* find all users */
router.get('/', (req, res) =&gt; {
User.find({},(err,data) =&gt;{
res.json(data)
})
/* find user by id */
router.get('/:id',(req, res) =&gt;{
User.findById(req.params.id, (err, data) =&gt;{
res.json(data)
})
/* delete user by id */
router.delete('/:id',async (req, res) =&gt;{
await User.findByIdAndDelete(req.params.id)
res.json({'message':'deleted'})
/* update */
router.put('/:id', async (req, res)=&gt;{
await User.findByIdAndUpdate(req.params.is, req.body)
res.json({'message':'updated'})
module.exports = router;
Server/index.js
const express = require('express');
const mongoose = require('mongoose');
const mongodb = require('mongodb');
const cors = require('cors');
mongoose.connect('mongodb://localhost:27017/admin?authSource=$[authSource] --username $[username]', {useNewUrlParser : true});
const app = express();
app.use(express.json());
app.use(cors());
app.use(express.urlencoded({extended:true}));
app.use('/api',require('./routes/index'));
const port = process.env.PORT || 8080;
app.listen(port);
module.exports =  new mongoose.model('User', newSchema);
React Side
import React, {Component} from 'react';
import axios from 'axios';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [],
id: 0,
name: '',
email: '',
password: '',
img: ''
}
componentDidMount() {
try {
axios.get('http://localhost:8080/api')
.then((res) =&gt; {
this.setState({
users: res.data,
id: 0,
name: '',
email: '',
password: '',
img: ''
})
})
} catch (e) {
console.log(e)
}
nameChange = event =&gt; {
this.setState({
name: event.target.value
})
emailChange = event =&gt; {
this.setState({
email: event.target.value
})
passwordChange = event =&gt; {
this.setState({
password: event.target.value
})
fileSelectedHandler = event =&gt;{
this.setState({
img : event.target.files[0]
})
submit(event, id) {
event.preventDefault();
const data = new FormData();
data.append('name', this.state.name);
data.append('password', this.state.password);
data.append('email', this.state.email);
data.append('image', this.state.img);
if (id === 0) {
axios.post('http://localhost:8080/api', data).then(()=&gt;{
this.componentDidMount()
})
} else {
axios.put('http://localhost:8080/api/'+id, data).then(()=&gt;{
this.componentDidMount()
})
}
deleteUser(id) {
try {
axios.delete('http://localhost:8080/api/' + id)
.then((res) =&gt; {
this.componentDidMount()
})
console.log('Deleted successfully.')
} catch (e) {
console.log(e)
}
editUser(id) {
try {
axios.get('http://localhost:8080/api/' + id)
.then((res) =&gt; {
console.log(res.data)
this.setState({
id:res.data._id,
name: res.data.name,
email: res.data.email,
password: res.data.password,
img : res.data.img.name
})
})
} catch (e) {
console.log(e)
}
render() {
return (
<div className="row"&gt;
<div className="col s6"&gt;
<form onSubmit={(e) =&gt; this.submit(e, this.state.id)}&gt;
<div className="input-field col s12"&gt;
<i className="material-icons prefix"&gt;person</i&gt;
<input value={this.state.name} onChange={(e) =&gt; this.nameChange(e)} type="text" id="autocomplete-input"
className="autocomplete" required/&gt;
<label htmlFor="autocomplete-input"&gt;Name</label&gt;
</div&gt;
<div className="input-field col s12"&gt;
<i className="material-icons prefix"&gt;mail</i&gt;
<input value={this.state.email} onChange={(e) =&gt; this.emailChange(e)} type="email" id="autocomplete-input"
className="autocomplete" required/&gt;
<label htmlFor="autocomplete-input"&gt;Email</label&gt;
</div&gt;
<div className="input-field col s12"&gt;
<i className="material-icons prefix"&gt;vpn_key</i&gt;
<input value={this.state.password} onChange={(e) =&gt; this.passwordChange(e)} type="password" id="autocomplete-input"
className="autocomplete" required/&gt;
<label htmlFor="autocomplete-input"&gt;Password</label&gt;
</div&gt;
<div className="input-field col s12"&gt;
<input type="file" name="file" onChange={(e) =&gt; this.fileSelectedHandler(e)}/&gt;
</div&gt;
<br/&gt;
<button className="btn waves-effect waves-light right blue" type="submit" name="action"&gt;Submit
<i className="material-icons right"&gt;send</i&gt;
</button&gt;
</form&gt;
</div&gt;
<div className="col s6"&gt;
<table&gt;
<thead&gt;
<tr&gt;
<th&gt;Name</th&gt;
<th&gt;Email</th&gt;
<th&gt;Password</th&gt;
<th&gt;IMG</th&gt;
<th&gt;Edit</th&gt;
<th&gt;Delete</th&gt;
</tr&gt;
</thead&gt;
<tbody&gt;
{this.state.users.map(user =&gt;
<tr key={user._id}&gt;
<td&gt;{user.name}</td&gt;
<td&gt;{user.email}</td&gt;
<td&gt;{user.password}</td&gt;
<td&gt;
<img src="./public/uploads/user.img.name" width="80"/&gt;
</td&gt;
<td&gt;
<button onClick={(e) =&gt; this.editUser(user._id)}
className="btn waves-effect waves-light green" type="submit" name="action"&gt;
<i className="material-icons right"&gt;edit</i&gt;
</button&gt;
</td&gt;
<td&gt;
<button onClick={(e) =&gt; this.deleteUser(user._id)}
className="btn waves-effect waves-light red" type="submit" name="action"&gt;
<i className="material-icons right"&gt;delete</i&gt;
</button&gt;
</td&gt;
</tr&gt;
)}
</tbody&gt;
</table&gt;
</div&gt;
</div&gt;
);
export default App;

Here is the accepted answer: I can see two problems in your code.
On the server side the uploaded file is available under file-property on the request object not the body-property. Also you need to set the name to the uploaded file on the multer single-call, i.e. image:
router.post('/', upload.single('image'), (req,res)=&gt;{
const image = req.file; // req.file contains the image
// req.body holds the other fields like name, email, ...
On the react side you should send formData instead of a json (json is the default):
const data = new FormData();
data.append('image', this.state.img);
data.append('email', this.state.name);
// ... append the remaining fields
axios.post('http://localhost:8080/api', data)
.then(() =&gt; {
this.componentDidMount()
// in the view also use the correct name
<input type="file" name="image" onChange={(e) =&gt; this.fileSelectedHandler(e)}/&gt;
Comment for this answer: Unfortunately I can't test it myself right now, but I think you need to add a body-parser instead of `express.json()`. Check these answers please ->
https://stackoverflow.com/a/43197040/3761628
https://stackoverflow.com/a/61025053/3761628
Comment for this answer: I tried to implement what you said, I edited the code blocks that I shared in my question. Can you check if I ask? This time there is no post request, previously the fields such as name, password, email could be registered on mongodb, but not currently. Is form data incorrect?


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2020:00:04/05/20', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<javascript><node.js><json><reactjs><mongodb>', 'Title': 'I cannot upload files to the directory I specified using node js multer', 'ViewCount': 412, 'id': 61041090, 'user_AboutMe': '<p>a developer with lot of questions</p>\n', 'user_AccountId': 16443208.0, 'user_DisplayName': 'meren', 'user_Reputation': 432.0, 'user_Views': 114.0, 'user_id': 12008735.0}}