Postman working fine with my backend code. I used form-data and put a random file. It uploaded successfully to image folder but when it come to React, It is not uploading, it showing error on backend and saying filename is not defined. I don't understand the error.
I think my front code is not working. I'm new to this. Here is my code:
function Regstudent () {
const [errorMessage, setErrorMessage] = useState("")
let navigate = useNavigate();
async function handleRegister(e) {
e.preventDefault()
const form = e.target
const user = {
email: form[0].value,
name: form[1].value,
gender: form[2].value,
password: form[3].value,
batch: form[4].value,
image:form[5].files
}
try {
const res = await fetch("http://localhost:8000/api/studentregister", {
method: "POST",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(user)
})
const data = await res.json()
setErrorMessage(data.message)
} catch (err) {
setErrorMessage(err)
}
}
<form encType='multipart/form-data' onSubmit={(e) => handleRegister(e)}>
<input placeholder='Mail Address' className='umail' type="email" name="email" id="email" required />
<br />
<input placeholder='Full Name' className='fname' type="text" name="name" id="name" required />
<br />
<input placeholder='Gender' className='gender' type="text" name="gender" id="gender" required/>
<br />
<input placeholder='Password' className='password' name="password" type="password" required/>
<br />
<select name="batch" type="select" required>
<option value="FSD">FSD</option>
<option value="CEH">CEH</option>
<option value="AI">AI</option>
</select>
<br />
<input type="file" accept=".png, .jpg, .jpeg" name="image" />
<br />
<input type="submit" className='regbutton' value="Register" />
</Form>
BACK END (Express with Multer):
//multer & uuid
const storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'images');
},
filename: function(req, file, cb) {
cb(null, uuidv4() + '-' + Date.now() + path.extname(file.originalname));
}
});
const fileFilter = (req, file, cb) => {
const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if(allowedFileTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
}
let upload = multer({ storage, fileFilter });
//POST
app.post("/api/studentregister", upload.single('image'), async(req,res)=>{
const user = req.body;
//check user name or pswd is taken before
const takenEmail = await Users.findOne({email: user.email})
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/i;
if (takenEmail){
res.json ({message: "Email has already been taken"})
}else if(!regex.test(user.email)) {
res.json ({message:"Email is invalid"});
}
else{
user.password = await bcrypt.hash(req.body.password, 10)
const dbUser = new Users({
email: user.email.toLowerCase(),
name: user.name,
gender:user.gender,
password: user.password,
batch:user.batch,
image: req.file.filename,
role: "user"
})
dbUser.save()
res.json({message: "Success"})
}
})
An easy way to send files with fetch is to use the FormData object, witch allows to send multipart/form-data. Like so :
async function handleRegister(e) {
e.preventDefault()
const formData = new FormData(e.target);
try {
const res = await fetch("http://localhost:8000/api/studentregister", {
method: "POST",
body: formData
})
const data = await res.json()
setErrorMessage(data.message)
} catch (err) {
setErrorMessage(err)
}
}