1

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)=>{

    user = new User({
        name:req.body.name,
        email:req.body.email,
        password:req.body.password,
        img: req.file
    });

    user.save(()=>{
        res.json(user)
    })
});

/* find all users */
router.get('/', (req, res) => {
    User.find({},(err,data) =>{
        res.json(data)
    })
});

/* find user by id */
router.get('/:id',(req, res) =>{
    User.findById(req.params.id, (err, data) =>{
        res.json(data)
    })
});

/* delete user by id */
router.delete('/:id',async (req, res) =>{
    await User.findByIdAndDelete(req.params.id)
    res.json({'message':'deleted'})
});

/* update */
router.put('/:id', async (req, res)=>{
    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) => {
                    this.setState({
                        users: res.data,
                        id: 0,
                        name: '',
                        email: '',
                        password: '',
                        img: ''
                    })
                })
        } catch (e) {
            console.log(e)
        }
    }

    nameChange = event => {
        this.setState({
            name: event.target.value
        })
    }

    emailChange = event => {
        this.setState({
            email: event.target.value
        })
    }

    passwordChange = event => {
        this.setState({
            password: event.target.value
        })
    }

    fileSelectedHandler = event =>{
        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(()=>{
                this.componentDidMount()
            })

        } else {
            axios.put('http://localhost:8080/api/'+id, data).then(()=>{
                this.componentDidMount()
            })
        }
    }

    deleteUser(id) {
        try {
            axios.delete('http://localhost:8080/api/' + id)
                .then((res) => {
                    this.componentDidMount()
                })
            console.log('Deleted successfully.')
        } catch (e) {
            console.log(e)
        }
    }

    editUser(id) {
        try {
            axios.get('http://localhost:8080/api/' + id)
                .then((res) => {
                    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">
                <div className="col s6">
                    <form onSubmit={(e) => this.submit(e, this.state.id)}>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">person</i>
                            <input value={this.state.name} onChange={(e) => this.nameChange(e)} type="text" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Name</label>
                        </div>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">mail</i>
                            <input value={this.state.email} onChange={(e) => this.emailChange(e)} type="email" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Email</label>
                        </div>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">vpn_key</i>
                            <input value={this.state.password} onChange={(e) => this.passwordChange(e)} type="password" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Password</label>
                        </div>
                        <div className="input-field col s12">
                            <input type="file" name="file" onChange={(e) => this.fileSelectedHandler(e)}/>
                        </div>
                        <br/>
                        <button className="btn waves-effect waves-light right blue" type="submit" name="action">Submit
                            <i className="material-icons right">send</i>
                        </button>
                    </form>
                </div>
                <div className="col s6">
                    <table>
                        <thead>
                        <tr>
                            <th>Name</th>
                            <th>Email</th>
                            <th>Password</th>
                            <th>IMG</th>
                            <th>Edit</th>
                            <th>Delete</th>
                        </tr>
                        </thead>
                        <tbody>
                        {this.state.users.map(user =>
                            <tr key={user._id}>
                                <td>{user.name}</td>
                                <td>{user.email}</td>
                                <td>{user.password}</td>
                                <td>
                                    <img src="./public/uploads/user.img.name" width="80"/>
                                </td>
                                <td>
                                    <button onClick={(e) => this.editUser(user._id)}
                                            className="btn waves-effect waves-light green" type="submit" name="action">
                                        <i className="material-icons right">edit</i>
                                    </button>
                                </td>
                                <td>
                                    <button onClick={(e) => this.deleteUser(user._id)}
                                            className="btn waves-effect waves-light red" type="submit" name="action">
                                        <i className="material-icons right">delete</i>
                                    </button>
                                </td>
                            </tr>
                        )}
                        </tbody>
                    </table>
                </div>
            </div>
        );
    }
}

export default App;

1 Answer 1

1

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)=>{
...
    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(() => {
    this.componentDidMount()
});

// in the view also use the correct name
...
<input type="file" name="image" onChange={(e) => this.fileSelectedHandler(e)}/>
...
Sign up to request clarification or add additional context in comments.

2 Comments

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?
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 -> stackoverflow.com/a/43197040/3761628 stackoverflow.com/a/61025053/3761628

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.