Unable to upload ( image + user data ) from react to node.js backend - node.js

When i click the register button then the REGISTER_USER function is called and then it creates a form obj with all the data and post it to the backend . i don't know why it is giving 500 error , cors error even tough i added cors in my app.js (node.js file)
Please help me with this issue ! Thanks in advance ...
Error
This is my backend Code
This implementsthe upload file and the user data to the data base
const imageStorage = multer.diskStorage({
destination: "./assets/images/Customers",
filename: (req, file, cb) => {
cb(
null,
file.originalname.split(".")[0] +
"-" +
Date.now() +
"." +
file.originalname.split(".")[1]
);
},
});
const upload_image = multer({
storage: imageStorage,
limits: {
fileSize: 10000000,
},
fileFilter(req, file, cb) {
if (!file.originalname.match(/\.(png|jpg)$/)) {
return cb(new Error("Only Png / Jpg format is accepted"));
}
cb(undefined, true);
},
});
router.post("/create-user", upload_image.single("image") , async (req, res) => {
try{
console.log(req.body)
console.log(req.file.filename)
let isPresent = await User.findOne({Name : req.body.Email.toLowerCase()})
if(isPresent !== null){
return res.status(400).json({ success : false , message : "Customer already present in the data base!"})
}else{
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.Password , salt)
let data = {...req.body , Name : req.body.Name.toLowerCase() , Password : hashedPassword , Email : req.body.Email.toLowerCase() , ProfilePic : req.file.filename};
console.log(data)
let Created_Customer = await User.create(data)
return res.status(200).json({success : true , message : "Successfully created the customer!" , Customer : Created_Customer});
}
}catch(err){
return res.status(500).json({success : false , message : err});
}
});
This is my FrontEnd Form Code
Function that post the data
const [adminData , setAdminData] = useState({
Name : "" ,
Email : "",
Password : "",
Role : "admin",
file : ""
})
const REGISTER_USER = async (e) =>{
e.preventDefault()
const formData = new FormData()
formData.append("Name" , adminData.Name)
formData.append("Email" , adminData.Email)
formData.append("Role" , adminData.Role)
formData.append("Password" , adminData.Password)
formData.append("image" , adminData.file)
const res = await fetch("http://localhost:5000/api/create-user" , {
method : "POST",
body : formData
})
console.log(res)
}
form
<form onSubmit={REGISTER_USER}>
<div>
<span>Name</span>
<span>
<input type="text" name ="Name" value ={adminData.Name} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<PersonOutlineRoundedIcon/>
</span>
</div>
<div>
<span>Email</span>
<span>
<input type="text" name ="Email" value ={adminData.Email} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<PersonOutlineRoundedIcon/>
</span>
</div>
<div >
<span>Password</span>
<span >
<input type="password" name ="Password" value ={adminData.Password} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
<VisibilityOutlinedIcon />
</span>
</div>
<span>
<input type="file" name ="file" value ={adminData.file} onChange={(e) => setAdminData({...adminData , [e.target.name] : e.target.value})}/>
</span>
<button type="submit">
<span>Register</span>
<ArrowForwardOutlinedIcon/>
</button>
</form>
Data is recieved in this format at the backend

Related

Unable to signup once login detail have been entered

I'm pretty new to React & node.js , and have attempted to create a chat messaging app. However im unable to access the rest of my app as every-time i sign in there is an error stating:
**Uncaught (in promise) Error: Request failed with status code 404
at createError (createError.js:16:1)
at settle (settle.js:17:1)
at XMLHttpRequest.onloadend (xhr.js:66:1)**
Auth.jsx file in client server
import React, {useState} from 'react';
import Cookies from 'universal-cookie';
import axios from 'axios';
import signinImage from '../assets/Group 2.png';
const cookies = new Cookies();
//forming the inital state of input fields
const initialState = {
fullName:'',
username:'',
password:'',
confirmPassword:'',
phoneNumber:'',
avatarURL:'',
}
const Auth = () => {
const [form, setForm] = useState(initialState);
const [isSignup , setIsSignup] = useState(true);
const handleChange = (e) => {
setForm({...form,[e.target.name]: e.target.value});
}
const handleSubmit = async (e)=>{
e.preventDefault();
const {username , password , phoneNumber , avatarURL } = form;
const URL = 'http://localhost:5009/auth'
//making requests to different url backened each time
const {data : { token ,userId , hashedPassword , fullName }} = await axios.post(`${URL}/${isSignup ? 'Sign Up ' : 'Sign In'}`,{
username , password , fullName: form.fullName , phoneNumber , avatarURL,
})
//storing data in cookies
cookies.set('token ' , token )
cookies.set('username ' , username )
cookies.set('fullName' , fullName)
cookies.set('userId ' , userId )
if (isSignup){
cookies.set('phoneNumber' , phoneNumber )
cookies.set('avatarURL' , avatarURL)
cookies.set('hashedPassword' , hashedPassword )
}
//reloads application
window.location.reload();
}
//changing state of my sign up screen depending on the state before
const switchMode = () => {
setIsSignup((prevIsSignup) => !prevIsSignup);
}
return (
<div className=" auth__form-container">
<div className="auth__form-container_fields">
<div className="auth__form-container_fields-content">
<p>{isSignup ? 'Sign up' : 'Sign In'}</p>
<form onSubmit= {handleSubmit}>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="fullName">Full Name</label>
<input
name="fullName"
type="text"
placeHolder= "Full Name"
onChange={handleChange}
required
/>
</div>
) }
<div className= "auth__form-container_fields-content_input">
<label htmlFor="username">Username</label>
<input
name="username"
type="text"
placeHolder= "Username"
onChange={handleChange}
required
/>
</div>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="phoneNumber">Phone Number</label>
<input
name="phoneNumber"
type="text"
placeHolder= "Phone Number"
onChange={handleChange}
required
/>
</div>
) }
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="avatarURL">Avatar URL</label>
<input
name="avatarURL"
type="text"
placeHolder= "Avatar URL"
onChange={handleChange}
required
/>
</div>
) }
<div className= "auth__form-container_fields-content_input">
<label htmlFor="password">Password</label>
<input
name="password"
type="password"
placeHolder= "Password"
onChange={handleChange}
required
/>
</div>
{isSignup &&(
<div className= "auth__form-container_fields-content_input">
<label htmlFor="confirmPassword">Confirm Password</label>
<input
name="confirmPassword"
type="password"
placeHolder= "Confirm Password"
onChange={handleChange}
required
/>
</div>
) }
<div className="auth__form-container_fields-content_button">
<button>{isSignup ? "Sign up " : "Sign In"}</button>
</div>
</form>
<div className="auth__form-container_fields-account">
<p>
{isSignup
? "Already have an account?"
:"Dont have an account ?"
}
<span onClick={switchMode}>
{isSignup ? ' Sign In' : ' Sign up'}
</span>
</p>
</div>
</div>
</div>
<div className="auth__form-container_image">
<img src = {signinImage} alt ="Sign In" />
</div>
</div>
)
}
export default Auth
Below is the code for files in my server folder :
index.js
const express = require ('express');
const cors = require ('cors');
//adding routes for sign in + registrationn//
const authRoutes = require("./routes/auth.js");
const app = express ();
const PORT = process.env.PORT || 5009;
require ('dotenv').config();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded());
app.get('/' , (req,res) => {
res.send('ne, world');
});
app.use('/auth', authRoutes);
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Auth.js file in Controllers folder:
const { connect } = require('getstream');
const bcrypt = require('bcrypt');
const StreamChat = require('stream-chat').StreamChat;
const crypto = require('crypto');
require('dotenv').config();
const api_key = process.env.STREAM_API_KEY;
const api_secret = process.env.STREAM_API_SECRET;
const app_id = process.env.STREAM_APP_ID;
const signup = async (req, res) => {
try {
const { fullName, username, password, phoneNumber } = req.body;
const userId = crypto.randomBytes(16).toString('hex');
const serverClient = connect(api_key, api_secret, app_id);
const hashedPassword = await bcrypt.hash(password, 10);
const token = serverClient.createUserToken(userId);
res.status(200).json({ token, fullName, username, userId, hashedPassword, phoneNumber });
} catch (error) {
console.log(error);
res.status(500).json({ message: error });
}
};
const login = async (req, res) => {
try {
const { username, password } = req.body;
const serverClient = connect(api_key, api_secret, app_id);
const client = StreamChat.getInstance(api_key, api_secret);
const { users } = await client.queryUsers({ name: username });
if(!users.length) return res.status(400).json({ message: 'User not found' });
const success = await bcrypt.compare(password, users[0].hashedPassword);
const token = serverClient.createUserToken(users[0].id);
if(success) {
res.status(200).json({ token, fullName: users[0].fullName, username, userId: users[0].id});
} else {
res.status(500).json({ message: 'Incorrect password' });
}
} catch (error) {ads
console.log(error);
res.status(500).json({ message: error });
}
};
module.exports = { signup, login }
Auth.js file in routes folder
const express = require ('express');
const { signup, login } = require('../controllers/auth.js');
const router = express.Router();
//initialising my 2 different routes //
//post route sending data from frontend to backend
router.post('/signup', signup);
router.post('/login', login);
module.exports = router;
Any thought on what im doing wrong or can implement to change these errors would be much appreciated !

Multer not able to get the filename

I'm not able to get the filename or path from Multer. This is what I've done so far:
uploadcsv.js
const fileUpload = multer({
limits: 500000,
storage:multer.diskStorage({
destination: (req, file, cb) =>{
cb(null,'upload/csv')
},
filename: (req, file, cb) =>{
const ext = MIME_TYPE_MAP[file.mimetype]
cb(null, uuid + '.' + ext)
},
fileFilter: (req, file, cb) =>{
const isValid = !!MIME_TYPE_MAP[file.mimetype]
let error = isValid ? null : new Error('Invalid mime type')
cb(error, isValid)
}
})
})
Then the route api:
router.post('/contact/importcontact', JWTAuthenticationToken, fileUpload.single('csv'), async (req, res) => {
console.log(req.body)
console.log(req.file.filename)
const csvFilePath = req.file.filename
const stream = fs.createReadStream(csvfile);
const account= await Account.findOne({ acctid: { "$eq": req.body.acctid } })
try {
if (req.file == undefined)
return res.status(400).send({ msg: 'No files were uploaded.' });
csvtojson()
.fromFile(csvFilePath)
.then((jsonObj) => {
console.log(jsonObj);
})
// Async / await usage
const jsonArray = await csvtojson().fromFile(csvFilePath);
res.json({ success: "Uploaded Successfully", status: 200 })
} catch (error) {
res.json({ message: error })
}
})
Lastly, the react importcustomer.js
const handleCSVChange = (e) => {
console.log(e.target.files[0])
setCsvData(e.target.files[0])
setUploadButtonData(e.target.files[0].name)
}
const uploadCSVData = async (e) => {
setLoading(true)
const formData = new FormData();
formData.append("csv", csvData);
console.log(formData)
e.preventDefault()
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', { formData: formData, acctid: lsData.acctid}, { withCredentials: true })
if (response.data.statusCode === "409") {
setMessage(response.data.msg)
setLoading(false)
}
else if (response.data.statusCode === "200") {
setLoading(false)
//history.push('/sources')
}
}
return (
<div className="col-12 grid-margin stretch-card">
<div className="card">
<div className="card-body">
<h4 className="card-title">Import Customer Data From CSV</h4>
<form className="forms-sample" enctype="multipart/form-data">
<div className="form-group">
<label for="files" className="btn btn-primary">{uploadButtonData}
<input id="files" type="file" name="csv" className="form-control" hidden accept="*.csv" onChange={handleCSVChange} /></label>
</div>
<button className="btn btn-primary" onClick={uploadCSVData} style={{ float: "right", width: "7rem" }} type="button">
{loading && <i className="fa fa-refresh fa-spin"></i>}
Upload CSV</button>
<div className="mt-3" style={{ textAlign: "center" }}>
<span id="msg" style={{ color: "red" }}>{message}</span>
</div>
</form>
</div>
</div>
</div>
)
Though I'm able to console.log(req.body) and console.log(e.target.files[0]) and getting the acctid and filename but returned empty for the console.log(formData) and console.log(req.file.filename) returned undefined. What have I missed? Many thanks in advance and greatly appreciate any helps. Thanks again
I have managed to solves this by appending the acctid to formData:
const formData = new FormData();
formData.append("csv", csvData);
formData.append("accctid", lsData.acctid);
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', formData, { withCredentials: true })

file upload with axioso is showing undefined in multer

I am trying to upload file using react and axios to node backend using multer.
when i use form as :
<form action = '/article/add' method="POST" className = {adminStyle.add_article_form} enctype="multipart/form-data">
<input type='text' className={adminStyle.add_article_input_title} autoComplete = 'off' name='title' placeholder='Title' value = {state.title} onChange={changeHandler}/>
<select name='category' value = {state.category} onChange={changeHandler}>
{options}
</select>
<input type="file" name='thumbnail' className={adminStyle.add_article_input_file} onChange={changeFileHandler}/>
<textarea type = 'text' name='body' className={adminStyle.add_article_textarea} rows='30' cols='100' value = {state.body} onChange={changeHandler}></textarea>
<button type='submit'>Submit</button>
</form>
it works fine but when using axios the file is undefined:
I used axios as:
const [state,setState] = useState({
title: '',
category: 'Choose one',
body: '',
thumbnail: ''
})
const changeFileHandler = (e) => {
setState({ thumbnail: e.target.files[0] })
}
const postArticle = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('thumbnail', state.thumbnail)
axios.post('/article/add', state,config).then(data => console.log(data))
}
<form onSubmit={postArticle} className = {adminStyle.add_article_form} enctype="multipart/form-data">
<input type='text' className={adminStyle.add_article_input_title} autoComplete = 'off' name='title' placeholder='Title' value = {state.title} onChange={changeHandler}/>
<select name='category' value = {state.category} onChange={changeHandler}>
{options}
</select>
<input type="file" name='thumbnail' className={adminStyle.add_article_input_file} onChange={changeFileHandler}/>
<textarea type = 'text' name='body' className={adminStyle.add_article_textarea} rows='30' cols='100' value = {state.body} onChange={changeHandler}></textarea>
<button type='submit'>Submit</button>
</form>
My backend is as follow:
const storage = multer.diskStorage({
destination: path.join(__dirname, '..', '../public/uploads'),
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
function checkFileType(file, cb){
// Allowed extension name
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('thumbnail')
router.post('/add',(req, res)=>{
upload(req,res, (err) => {
console.log(req.file)
})
});
can anyone help me with this? I am really stuck. I need to upload the image in the backend.
You are passing state and not formData as the body of the request. You should change this line:
axios.post('/article/add', state,config).then(data => console.log(data))
with this line:
axios.post('/article/add', formData ,config).then(data => console.log(data))

Images not appearing in the MongoDB database

I am uploading a form that contains an image to my mongodb database, all the data is there as should be however the images are not appearing on the database. Does it have anything to do with the fact i an unable to add propertyImage: req.file.path as I get the error of 'typeError cannot read property of 'path' od undefined'. The reason I want them in the database is to enable me to fetch them and attach the images to the relevant product.
I have the backend code below, as for the front end I am going to assume that I need to create something with formData in order to send the the text fields with the image. If so could someone point me in the right direction as I am not sure where to start so that It wont affect my user authorization set up as detailed below.
const express = require('express');
const userRouter = express.Router();
const passport = require('passport');
const passportConfig = require('../passport');
const JWT = require('jsonwebtoken');
const User = require('../models/User');
const Property = require('../models/Property');
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, "./uploads/");
},
filename: (req, file, callback) => {
callback(null, file.originalname);
}
})
const upload = multer({storage: storage});
const signToken = userID => {
return JWT.sign({
iss : "Moove",
sub : userID
},"Moove",{expiresIn :"1h"});
}
userRouter.post('/register',(req,res)=>{
const {username,name,email,password} = req.body;
User.findOne({email},(err,user)=>{
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
if(user)
res.status(400).json({message : {msgBody: "Email has already been used, Please log in", msgError : true}});
else{
const newUser = new User({username,name,email,password});
newUser.save(err=>{
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else
res.status(201).json({message : {msgBody: "Account Successfully Created", msgError : false}});
});
};
});
});
userRouter.post('/login',passport.authenticate('local',{session : false}),(req,res)=>{
if(req.isAuthenticated()){
const {_id,username,password} = req.user;
const token = signToken(_id);
res.cookie('access_token',token,{httpOnly: true, sameSite:true});
res.status(200).json({isAuthenticated : true,user : {username,password}});
}
});
userRouter.get('/logout',passport.authenticate('jwt',{session : false}),(req,res)=>{
res.clearCookie('access_token');
res.json({user:{username:''},success : true})
});
userRouter.post('/property', upload.single('propertyImage'),passport.authenticate('jwt',{session : false}),(req,res)=>{
console.log(req.file);
const property = new Property({
street: req.body.street,
town: req.body.town,
area: req.body.area,
PostCode: req.body.PostCode,
NoBeds: req.body.NoBeds,
NoBath: req.body.NoBath,
NoLivingRooms: req.body.NoLivingRooms,
askingPrice: req.body.askingPrice,
propertyImage: req.file
});
property.save(err=> {
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else{
req.user.properties.push(property);
req.user.save(err=> {
if(err)
res.status(500).json({message : {msgBody: "Error has occured", msgError : true}});
else
res.status(200).json({message: {msgBody: "Successfully created property", msgError : false}});
})
}
})
});
userRouter.get('/properties',passport.authenticate('jwt',{session : false}),(req,res)=>{
User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else{
res.status(200).json({properties : document.properties, authenticated : true});
}
});
});
userRouter.get('/property',passport.authenticate('jwt',{session : false}),(req,res)=>{
User.findById({_id : req.user._id}).populate('properties').exec((err,document)=>{
if(err)
res.status(500).json({message : {msgBody : "Error has occured", msgError: true}});
else{
res.status(200).json({properties : document.properties, authenticated : true});
}
});
});
userRouter.get('/authenticated',passport.authenticate('jwt',{session : false}),(req,res)=>{
const {username} = req.user;
res.status(200).json({isAuthenticated : true, user: {username}})
});
module.exports = userRouter;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
import React, {useState,useContext, useEffect} from 'react'
import PropertyItem from './PropertyItem';
import PropertyService from '../Services/PropertyService';
import Message from './Message'
import {AuthContext} from '../Context/AuthContext';
const Properties = props =>{
const [property,setProperty] = useState({
// propertyImage: "",
street : "",
town : "",
area : "",
PostCode : "",
NoBeds : "",
NoBath : "",
NoLivingRooms : "",
askingPrice: "",
})
const [properties,setProperties] = useState ([]);
// const [propertyImage,setPropertyImage] = useState ([]);
const [message,setMessage] = useState(null);
const authContext = useContext(AuthContext);
useEffect(()=>{
PropertyService.getProperties().then(data =>{
setProperties(data.properties);
});
},[]);
const onSubmit = e =>{
e.preventDefault();
PropertyService.postProperty(property).then(data =>{
const {message } = data;
resetForm();
if(!message.msgError){
PropertyService.getProperties().then(getData =>{
setProperties(getData.properties);
setMessage(message);
});
}
else if(message.msgBody === "UnAuthorized"){
setMessage(message);
authContext.setUser({username : ""});
authContext.setIsAuthenticated(false);
}
else{
setMessage(message);
}
},[]);
}
const onChange = e =>{
setProperty({...property,[e.target.name] : e.target.value})
}
// const onChangefile = e =>{
// setPropertyImage(e.target.files[0])
// }
const resetForm = ()=>{
setProperty({
propertyImage: "",
street : "",
town : "",
area : "",
PostCode : "",
NoBeds : "",
NoBath : "",
NoLivingRooms : "",
askingPrice : "",
});
}
return(
<div>
<ul className="">
{
properties.map((property) =>{
return <PropertyItem key={property._id}
property={property}
street={property.street}
town={property.town}
area={property.area}
PostCode={property.PostCode}
NoBeds={property.NoBeds}
NoBath={property.NoBath}
NoLivingRooms={property.NoLivingRooms}
askingPrice={property.askingPrice}
propertyImage={property.propertyImage}
/>
},[])
}
</ul>
<br/>
<form onSubmit={onSubmit} encType="multipart/form-data">
<label htmlFor="street">Street Name</label>
<input type="text"
name="street"
value={property.street}
onChange={onChange}
className=""
placeholder="street name"/>
<label htmlFor="town">Town</label>
<input type="text"
name="town"
value={property.town}
onChange={onChange}
className=""
placeholder="town"/>
<label htmlFor="area">Area</label>
<input type="text"
name="area"
value={property.area}
onChange={onChange}
className=""
placeholder="area"/>
<label htmlFor="postcode">Postcode</label>
<input type="text"
name="PostCode"
value={property.PostCode}
onChange={onChange}
className=""
placeholder="Postcode"/>
<label htmlFor="NoBeds">Beds</label>
<input type="number"
name="NoBeds"
value={property.NoBeds}
onChange={onChange}
className=""
placeholder="Number of beds"/>
<label htmlFor="NoBath">Bathrooms</label>
<input type="number"
name="NoBath"
value={property.NoBath}
onChange={onChange}
className=""
placeholder="Number of bathrooms"/>
<label htmlFor="NoLivingRooms">Living Rroom</label>
<input type="number"
name="NoLivingRooms"
value={property.NoLivingRooms}
onChange={onChange}
className=""
placeholder="Number of living rooms"/>
<label htmlFor="askingPrice">Asking Price(£)</label>
<input type="number"
name="askingPrice"
value={property.askingPrice}
onChange={onChange}
className=""
placeholder="£249,999"/>
<label htmlFor="propertyImage">Property Images</label>
<input type="file"
filename="propertyImage"
onChange={onChange}
className=""
placeholder="Upload property images"/>
<button className=""
type="submit">Submit</button>
</form>
{message ? <Message message={message}/> : null}
</div>
);
}
export default Properties
You have to deal with your file input <input type="file"... differently to normal text fields. File inputs react differently to normal fields. They take an on change event, which updates when a user selects a file, and converts to a blob. You need to convert this to base64 and then send the base64 to the server (or a proper image hosting service such as cloudinary).
Here's a demo:
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="file" id='file'/>
<script src='./app.js'></script>
</body>
</html>
app.js
const fileReader = document.getElementById('file')
const getBase64 = (file) => {
return new Promise((resolve, reject) => {
const fr = new FileReader()
console.log(file instanceof Blob) // Should be true
fr.readAsDataURL(file)
fr.onerror = reject
fr.onload = function () {
resolve(fr.result)
}
})
}
fileReader.addEventListener('change', (e) => {
console.log(e.target.files[0])
getBase64(e.target.files[0]).then((res) => console.log(res) )
})
In the JS above, we are getting the file reader input as an element and setting an onChange event to it, which calls the getBase64 function. The getBase64 function returns a Promise, that is fulfilled after the file has been read. Inside that function, we create a new FileReader as fr, then call fr.readDataAsURL(file) which converts your file to base64, and then resolve it in fr.onload. You can then call the output of that using getBase64(file).then(res => doSomething(res)).
Create a directory with those 2 files, and then test out the functionality. When you select a file, you should see a really long string of characters (Base64), and this is what you should post to your image hosting service.
I believe you can post base64 to MongoDB, though it is not recommended.

POST http://localhost:5000/books/add 400 (Bad Request)

I am creating a Book store app using MERN. But when I am trying to upload a new book, it is returning 'POST http://localhost:5000/books/add 400 (Bad Request)'.
Not sure why it is happening, In this case, the book is not gating uploaded but the cover image is gatting store in/ uploads dir. But data is not going to the mongoose.
Using multer to upload bookcover and react with hooks
.
Please Help, Here is the code
backend\routes\Books.js
const router = require("express").Router();
let Book = require("../models/BookModel");
const multer = require('multer');
const storage = multer.diskStorage({
destination:function(req, file, cb){
cb(null, './uploads/');
},
filename:function(req, file, cb){
cb(null, file.originalname);
}
});
const fileFIlter = (req, file,cb) => {
if(file.mimetype === 'image/jpeg' || file.mimetype === 'image/png'){
cb(null, true);
}
else{
cb(null, false);
}
}
const upload = multer({storage:storage, limits:{
fileSize: 1024 * 1024 * 2
}});
router.route("/").get((req, res) => {
Book.find()
.then((books) => res.json(books))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/add").post(upload.single('cover'), (req, res) => {
console.log(req.file);
const name = req.body.name;
const author = req.body.author;
const price = req.body.price;
const summary = req.body.summary;
const cover = req.file.path;
const newBook = new Book({
name,
author,
price,
summary,
cover
});
newBook
.save()
.then(() => res.json("Book Added!"))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/:id").get((req, res) => {
Book.findById(req.params.id)
.then((book) => res.json(book))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/:id").delete((req, res) => {
Book.findByIdAndDelete(req.params.id)
.then(() => res.json("Book Deleted!"))
.catch((err) => res.status(400).json("Error: " + err));
});
router.route("/update/:id").post(upload.single('cover'),(req, res) => {
Book.findById(req.params.id)
.then((book) => {
book.name = req.body.name;
book.author = req.body.author;
book.price = req.body.price;
book.summary = req.body.summary;
book.cover = req.file.path;
book
.save()
.then(() => res.json("Book Updated!"))
.catch((err) => res.status(400).json("Error: " + err));
})
.catch((err) => res.status(400).json("Error: " + err));
});
module.exports = router;
and frontend\src\pages\AddBookPage.js
import {useState} from "react";
import axios from "axios";
const AddBookPage = () => {
const [Book, SetBook] = useState({
name:"",
author:"",
price:"",
summary:"",
cover:null
});
// Handel Input Change
const handleChange = (e) => {
SetBook({...Book,
[e.target.name]: e.target.value,
});
};
// Handel Input Change
const handleFileChange = (e) => {
SetBook({...Book,
[e.target.name]: e.target.files[0],
});
console.log(Book.cover)
};
// Update book to server
const handleSubmit = (e) => {
e.preventDefault();
console.log(Book.cover);
const formData = new FormData();
formData.append(
'cover',
Book.cover
);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
const book = {
name:Book.name,
author:Book.author,
price:Book.price,
summary:Book.summary,
cover:Book.cover.name
};
axios
.post(
`http://localhost:5000/books/add`, formData, config, book
)
.then((res) => console.log(res.data))
.catch((err) => console.log(err));
console.log(book);
};
return (
<main>
<div className="book_page book_edit_page">
<div className="book_edit_warp">
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Name</label>
<input
type="text"
className="form-control"
id="name"
name="name"
required
onChange={handleChange}
value={Book.name}
/>
</div>
<div className="form-group">
<label htmlFor="author">Author</label>
<input
type="text"
className="form-control"
id="author"
name="author"
required
onChange={handleChange}
value={Book.author}
/>
</div>
<div className="form-group">
<label htmlFor="price">Price</label>
<input
type="text"
className="form-control"
id="price"
name="price"
required
onChange={handleChange}
value={Book.price}
/>
</div>
<div className="form-group">
<label htmlFor="summary">Summary</label>
<textarea
type="text"
className="form-control"
id="summary"
name="summary"
required
onChange={handleChange}
value={Book.summary}
/>
</div>
<div className="form-group">
<label htmlFor="cover">Book Cover</label>
<input
type="file"
className="form-control"
id="cover"
name="cover"
required
onChange={handleFileChange}
/>
</div>
<button type="submit" className="btn btn-primary">
Update
</button>
</form>
</div>
</div>
</main>
)
}
export default AddBookPage;

Resources