I am trying to send formdata from react to express server. When sending json payload, i get what is expected. However, when sending data using formdata.append, i get empty req body.
I tried various solutions posted here for similar problem but nothing seemed to work for me.
Hope someone can help
app.js
require('./database/db')
const express = require('express')
const cors = require('cors')
const userRouter = require('./routes/user')
const menuRouter = require('./routes/menu')
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cors())
app.use(express.static('public'))
app.use(userRouter)
app.use(menuRouter)
app.listen(9000, () => console.log('Server started at port: 9000'))
route i want to call
router.post(
'/addMenu',
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
// body is empty here
})
react bootstrap form
import { Component } from 'react'
import axios from '../axios'
import { Link } from 'react-router-dom'
import { Button, Form, Card } from 'react-bootstrap'
export default class AddMenu extends Component {
constructor(props) {
super(props)
this.state = {
name: '',
price: '',
category: '',
image: '',
}
this.inputHandler = this.inputHandler.bind(this)
this.inputHandler = this.inputHandler.bind(this)
this.addMenu = this.addMenu.bind(this)
}
inputHandler = (e) => {
this.setState({
[e.target.name]: e.target.value,
})
}
fileHandler = (e) => {
this.setState({
image: e.currentTarget.files[0],
})
}
addMenu = (e) => {
e.preventDefault()
const { name, price, category, image } = this.state
const data = new FormData()
data.append('name', name)
data.append('price', price)
data.append('category', category)
data.append('file', image)
axios
.post('/addMenu', data)
.then((response) => {
if (response.data.success) {
alert(response.data.menu)
} else {
alert('something went wrong')
}
})
.catch()
}
render() {
return (
<div className='col-lg-12 col-centered' style={{ height: '44rem' }}>
<Card
style={{
width: '20rem',
marginLeft: '420px',
marginTop: '80px',
float: 'left',
height: '34rem',
}}
>
<Card.Img
variant='top'
src='https://image.freepik.com/free-vector/food-delivery-service-fast-food-delivery-scooter-delivery-service-illustration_67394-869.jpg'
/>
<Card.Body>
<Card.Title>Add Menu</Card.Title>
<Card.Text>
Although a great restaurant experience must include great food, a bad restaurant experience can be achieved through bad service alone.
Ideally, service is invisible.
</Card.Text>
<Button as={Link} to='/' variant='info'>
Go to Home
</Button>
</Card.Body>
</Card>
<Card
style={{
width: '22rem',
marginTop: '78px',
float: 'left',
height: '34rem',
}}
>
<Form className='add-menu' onSubmit={this.addMenu}>
<h2>Add Menu</h2>
<Form.Group controlId='formBasicName'>
<Form.Label>Restaurant Name</Form.Label>
<Form.Control
type='text'
name='name'
placeholder='Enter Restaurant Name'
value={this.state.name}
onChange={(event) => this.inputHandler(event)}
/>
</Form.Group>
<Form.Group controlId='formBasicPrice'>
<Form.Label>Enter Price</Form.Label>
<Form.Control type='text' name='price' placeholder='Price' value={this.state.price} onChange={(event) => this.inputHandler(event)} />
</Form.Group>
<Form.Group controlId='formBasicCategory'>
<Form.Label>Enter Category</Form.Label>
<Form.Control
name='category'
type='text'
placeholder='Enter Menu Category'
value={this.state.category}
onChange={(event) => this.inputHandler(event)}
/>
</Form.Group>
<Form.Group controlId='formBasicImage'>
<Form.Label>Enter Category</Form.Label>
<Form.Control name='image' type='file' onChange={this.fileHandler} />
</Form.Group>
<Button className='btn-lg btn-block' variant='info' type='submit'>
Add Menu
</Button>
</Form>
</Card>
<br />
<br />
<br />
</div>
)
}
}
routes/menu implementation
const router = require('express').Router()
const { verifyAuth } = require('../middleware/auth')
const upload = require('../middleware/fileUpload')
const Menu = require('../models/Menu')
const { check, validationResult } = require('express-validator')
// add a menu item
router.post(
'/addMenu',
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
if (req.authUser.userType === 'Restaurant') {
const validationErr = validationResult(req)
if (validationErr.isEmpty()) {
let image = null
const { name, price, category } = req.body
if (req.file) {
upload(req, res, (err) => {
if (err) {
response.status(500).json({ success: false, message: err })
} else {
image = req.file.filename
}
})
}
const newMenu = new Menu({ name, price, category, addedBy: req.authUser._id, image })
newMenu
.save()
.then((menu) => res.status(201).json({ success: true, message: 'Menu added', menu }))
.catch((error) => res.status(500).json({ success: false, message: error.message }))
} else {
res.status(400).json({ success: false, errors: validationErr.array() })
}
} else {
res.status(403).json({ success: true, message: 'Insufficient privileges' })
}
}
)
// get all menu items
router.get('/menus', (req, res) => {
Menu.find()
.populate('addedBy', '-_id name')
.then((menus) => res.status(200).json({ success: true, menus }))
.catch((error) => res.status(500).json({ success: false, message: error.message }))
})
module.exports = router
Even in Postman x-www-form-urlencoded sends the data but form-data does not
Form data will get empty object if there is no file given to it via routes like this.
import multer from 'multer';
router.post(
'/addMenu',
multer().single("keyNameForFile"),
[
check('name', 'Menu name is required!').not().isEmpty(),
check('price', 'Price is required!').not().isEmpty(),
check('category', 'Category is required!').not().isEmpty(),
],
verifyAuth,
(req, res) => {
console.log(req.body)
// body is empty here
})
Don't know what cause this behaviour but use form-data when you are sending some file like image doc etc.
You should set the Content-Type of your request header as Content-Type: application/x-www-form-urlencoded this will allow express to access you form data in the body
To set the header in axios you can perform it like this
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
and you perform a request to you backend with the header set like this
axios.post('/addMenu', data, config)
.then({ /*...*/});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With