Not getting image file in nodejs after posting from react - node.js

I'm sending the image file from react to nodejs. I used the SetImage function where the image file selected by the user is set to the 'myimage' state variable and from handleSubmit I'm posting the images to the '/blog/posts' endpoint using Axios. the image file is getting loaded on the 'myimage' state variable but as I posted using the Axios, I can't see all the data of the image file and giving me the empty object.
This is my React code:-
import React, { useState, useRef } from "react";
import './postblog.css';
import axios from '../axios';
const PostBlog = () => {
const [myimage,setImage] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
axios.post('/blog/posts', {
image:myimage
}).then((res) => {
console.log(res.body);
console.log('successfully posted');
});
}
const SetImage = (e)=>{
console.log(e.target.files[0]);
setImage(e.target.files[0]);
console.log(myimage);
}
return (
<div className="postblog">
<form onSubmit={handleSubmit} enctype="multipart/form-data">
<input type="file" placeholder="Choose your file" onChange={(e)=>{SetImage(e)}} name="myImage"/>
</div>
<button type="submit">Post</button>
</form>
</div>
);
}
export default PostBlog;
This is my Nodejs code:-
var storage = multer.diskStorage({
destination: function(req, res, cb) {
cb(null, './Routers/blog/uploads');
},
filename: function(req, file, cb) {
cb(null, Date.now() + file.originalname);
}
});
var upload = multer({
storage: storage,
limits: {
fieldsize: 1024 * 1024 * 3
}
});
blog.post('/posts', upload.single('myimage'), (req, res, next) => {
console.log(req.body);
console.log(details);
})
The output in the console I'm getting is an empty object

You should send file with content type as multipart/form-data but in your code you are sending file as application/json content type.
...
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('file', myimage);
const config = {
headers: {
'content-type': 'multipart/form-data'
}
};
axios.post('/blog/posts', formData, config).then((res) => {
console.log(res.body);
console.log('successfully posted');
});
}
...

Related

React Hooks and Axios Image Upload with Multer

I am trying to add the ability to upload an image and then update a user object with that image path. When I upload the image using Insomnia client and send the request, I am able to successfully add the image and path to MongoDB. NodeJS user route below:
const express = require ("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const Users = require("../models/users");
const auth = require("../middleware/auth");
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) => {
// reject a file
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png' || file.mimetype == "image/jpg") {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Only .png, .jpg and .jpeg format allowed!'));
}
};
const upload = multer({storage: storage, limits: {
fileSize: 1024 * 1024 * 5
},
fileFilter: fileFilter
});
// REQUEST TO FIND USER BY ID AND ADD A PROFILE PICTURE
router.put('/update/:id', upload.single('userImage'), (req, res) => {
Users.findById(req.params.id)
.then(user => {
user.userImage = req.file.path || user.userImage,
user
.save()
.then(() => res.json("The User is UPDATED succesfully!"))
.catch(err => res.status(400).json(`Error: ${err}`));
})
.catch(err => res.status(500).json(`Error: ${err}`));
console.log(req.body);
console.log(req.file);
});
However, when I test the code on the client I receive the following 500 error: ""Error: TypeError: Cannot read property 'path' of undefined." I am using React Hooks and Axios, code below:
import React, { useState, useContext } from 'react';
import Exit from '../cancel.svg';
import Modal from 'react-modal';
import { useForm } from "react-hook-form";
import axios from 'axios';
import UserContext from "../context/UserContext";
import { useHistory } from "react-router-dom";
Modal.setAppElement('#root');
const ProfilePicture = () => {
const [modalIsOpen, setModalIsOpen]= useState (true);
const { register, handleSubmit } = useForm ();
const [userImage, setUserImage] = useState();
const onSubmit = (data) => console.log(data);
const { userData } = useContext(UserContext);
const history = useHistory();
const changeOnClick = e => {
const users = {
userImage
};
console.log(users);
axios
.put(`http://localhost:5000/users/update/${userData.user.id}`, users)
.then(res => console.log(res.body))
.catch(err => {
console.log(err);
});
history.push("/Landing")
}
return(
<Modal isOpen={modalIsOpen} onRequestClose={() => setModalIsOpen(false)} className='finishBorder'>
<div className='border-bottom-two'>
<img onClick= {() => setModalIsOpen(false)} className='newexitButton'src={Exit} alt='X' />
<span className='lastThing'>One last thing! Add a profile picture</span>
</div>
<form onSubmit={handleSubmit(changeOnClick)} encType="multipart/form-data" >
<div>
<span className="dot"></span>
<input onChange={e => setUserImage(e.target.value)} ref = {register} type='file' name='userImage' className='picUploader'/>
{/* <button>submit</button> */}
</div>
<div>
<button type='submit' className='doneButton'>Done</button>
<div>
<span className='laterTwo'>I'll do this later</span>
</div>
</div>
</form>
</Modal>
)
}
export default ProfilePicture;
Appreciate the help!
What you are sending from the client is a "fakepath", not a file. To access the file from the input use:
setUserImage(e.target.files[0])
Also, I think multer only works with multipart/form-data, so you should check that, but is as easy as:
const formData = new FormData();
formData.append([image name], [image file]);
axios.post(`http://localhost:5000/users/update/${userData.user.id}`, formData, {
headers: { "Content-Type": "multipart/form-data" }})

Why does my DataForm not return as an object that my URL.createObjectURL is supposed to read?

All I am trying to accomplish is to give my users the option to upload images. I decided to use mongoDB as my database which means I must store photos locally and then send them to the DB. As far as I know, I am new. The object created by ImageName and ImageData isn't being passed properly to my axios post request
.post(`http://localhost:5000/api/image/uploadmulter/`, imageFormObj)
.then((data) => {
if (data.data.success) {
alert("Image has been successfully uploaded using multer");
this.setDefaultImage("multerImage");
}
})
Here is my route
const Image = require('../models/imageModel');
const ImageRouter = express.Router();
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb){
cb(null, './uploads/')
},
filename: function(req,file,cb){
cb(null, Date.now() + file.originalname);
}
});
const fileFilter = (req, file, cb) =>{
if(file.mimetype === 'image/jpeg' || file.mimetype ==='image/png'){
cb(null, true);
} else{
//rejects storing file
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits:{
fileSize:1024 *1024 * 5
},
fileFilter: fileFilter
});
// stores image in uploads folder using multers and creates a reference to the file
ImageRouter.route("/upload")
.post(upload.single('imageData'), (req, res, next) => {
console.log(req.body);
const newImage = new Image({
imageName: req.body.imageName,
imageData: req.file.path
});
newImage.save()
.then((result)=>{
console.log(result)
res.status(200).json({
success: true,
document: result
});
})
.catch((err)=> next(err))
});
module.exports = ImageRouter;
here is my model
const Schema = mongoose.Schema;
const ImageSchema = new Schema({
imageName:{
type: String,
default: "none",
required: true
},
imageData: {
type :String,
required: false
}
});
const Image = mongoose.model('Image' , ImageSchema)
module.exports = Image;
Here is my ImageUploader page that calls the function
import axios from 'axios';
import DefaultImg from '../assets/default-img.jpg';
import 'bootstrap/dist/css/bootstrap.min.css';
export default class ImageUploader extends Component {
constructor(props) {
super(props)
this.state = {
multerImage: DefaultImg
}
};
setDefaultImage = (uploadType) => {
if (uploadType === "multer") {
this.setState({multerImage: DefaultImg});
};
};
// function to upload image once it has been captured include multer and
// firebase methods
uploadImage(e, method) {
let imageObj = {};
if (method === "multer") {
let imageFormObj = new FormData();
imageFormObj.append("imageName", "multer-image-" + Date.now());
imageFormObj.append("imageData", e.target.files[0]);
console.log(imageFormObj)
// stores a readable instance of the image being uploaded using multer
this.setState({
multerImage: URL.createObjectURL(e.target.files[0])
});
axios
.post(`http://localhost:5000/api/image/uploadmulter/`, imageFormObj)
.then((data) => {
if (data.data.success) {
alert("Image has been successfully uploaded using multer");
this.setDefaultImage("multerImage");
}
})
.catch((err) => {
alert("Error while uploading image using multer");
this.setDefaultImage("multer");
});
}
};
render() {
return (
<div className="main-container">
<h3 className="main-heading">Image Upload App</h3>
<div className="image-container">
<div className="process">
<h4 className="process__heading">Process: Using Multer</h4>
<p className="process__details">Upload image to a node server, connected to a
MongoDB database, with the help of multer</p>
<input
type="file"
display="block"
className="process__upload-btn"
placeholder="Username"
onChange={(e) => this.uploadImage(e, "multer")
}/>
<img
src={this.state.multerImage}
alt="upload-image"
className="process__image"/>
</div>
</div>
</div>
);
};
};
and finally this is where it's being rendered
// import {EditProfile} from './EditProfile'
import DisplayCats from '../cats/DisplayCats'
// import Button from '#material-ui/core/Button';
import Axios from 'axios';
import ImageUploader from '../ImageUploader';
function ProfilePage(props) {
console.log(props.userInfo)
const user = props.userInfo
console.log(user)
console.log(user._id)
console.log(props.userInfo._id)
let [responseData,
setResponseData] = useState('');
// getLocation = () => {
// navigator
// .geolocation
// .getCurrentPosition(function (position) {
// console.log(position)
// });
// }
const clickHandler = (e) => {
this
.props
.history
.push('/DisplayCats')
}
// const setProfileImage = (event) => {
// Axios
// .post('http://localhost:5000/api/users/updateImage/' + user._id, {
// "_id": user._id,
// "profileImage": event.target.value
// })
// .then(res => {
// setResponseData(res.data)
// console.log(responseData)
// }, function (err) {
// console.log(err)
// })
// }
return (
<div style={{
color: "black"
}}>
<h5>This is {props.userInfo.firstName}'s Profile Page</h5>
<h5>Last name: {props.userInfo.lastName}</h5>
<h5>Age: {props.userInfo.age}</h5>
<h5>Location:{props.userInfo.location}</h5>
<h5>Image:{props.userInfo.profileImage}</h5>
<h5>Biography:{props.userInfo.biography}</h5>
<ImageUploader user={user}/>
{/* <div className="col-md-6 img">
<img
src={responseData.profileImage}
alt="profile image"
className="img-rounded"/>
</div> */}
<div className="row">
<DisplayCats user={user}/>
</div>
{/*
<Button
variant="outlined"
color="primary"
onClick={this.clickHandler}
component={this.EditProfile}
user={this.props.user}>
Edit Info
</Button> */}
</div>
)
}
export default ProfilePage;
I want my image data and and image name to be created into a URL for my other functions to read it. My error comes back as POST /api/image/uploadmulter/ 404 97.290 ms - 163
Perhaps im missing something but from the code you shared, you set your route as:
ImageRouter.route("/upload")
so, your client side code should be posting to: http://localhost:5000/upload
yet, your code does this:
.post(`http://localhost:5000/api/image/uploadmulter/`
You're getting a 404 error, which makes sense since this route hasn't been defined.
On a related note, I'd recommend using something like react-uploady, to manage the uploads on your client-side. It will save you a lot of code and bugs. Especially if you want to show preview or other related functionality (like: progress, cancel, retry, etc.).

File Upload from API Routes Next.js not working

I'm trying to upload a file to my server which I'm successfully able to do with my code, but I get a this console output from it:
API resolved without sending a response for /api/upload, this may result in a stalled requests.
The file is successfully put into the folder though.
I don't quite understand how I am not sending a response as to me I am.
What am I doing wrong?
Here is my form code:
const axios = require("axios").default;
class VideoUploadForm extends React.Component {
constructor(props) {
super(props);
this.state = {
file: null,
uploaded: false
};
}
onChangeHandler = event => {
this.setState({
selectedFile: event.target.files[0],
loaded: 0
});
};
onClickHandler = () => {
const data = new FormData();
data.append("video", this.state.selectedFile);
axios
.post("/api/upload", data, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.log(error);
});
};
render() {
return (
<div>
<form
action="#"
method="post"
encType="multipart/form-data"
target="transFrame"
>
<input type="file" name="video" onChange={this.onChangeHandler} />
<button onClick={this.onClickHandler}>upload</button>
</form>
<iframe
width="200"
height="100"
name="transFrame"
id="transFrame"
></iframe>
</div>
);
}
}
export default VideoUploadForm;
and the API
import multer from "multer";
export const config = {
api: {
bodyParser: false
}
};
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "public");
},
filename: function(req, file, cb) {
cb(null, "video.mp4");
}
});
var upload = multer({ storage: storage });
export default async (req, res) => {
upload.single("video")(req, {}, err => {
res.send(req.file.path);
res.end();
console.log(req.file); // do something with the file
});
};
This is where the problem is
res.send(req.file.path);
res.end();
res.send implicitly calls res.write followed by res.end. You should remove the second res.end.
Try
var upload = multer(storage);

Avatar is saved to MongoDB but no success message and rendering of avatar in component, using React and Multer

Depending on your viewpoint, I was able to get the most important part of getting a Avatar/Image in an app...pushing to the database (MongoDB in my case, Also the image gets added to my server folder).
However what I can't get working is the success modal to fire or the rendering of the image on the page, which is strange as the response.status === 200 and response.ok === true? I am using Multer in Express. (I am using fetch).
This is my ImageLoader component:
import React, { Component } from 'react';
import './ImageUploader.css';
import Modal from '../Modal/MyModal.jsx'
import DefaultImg from '../../static/profile-avatars/assets/default-img.jpg';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { modalStateOn, modalStateOff } from '../../store/index'
const API_URL = "http://localhost:8016";
class ImageUploader extends Component {
constructor(props) {
super(props);
this.state = {
multerImage: DefaultImg,
}
}
setDefaultImage(uploadType) {
if (uploadType === "multer") {
this.setState({
multerImage: DefaultImg
});
}
}
uploadImage(e, method) {
var { history, isLoggedIn, modalActive, modalStateOn, modalStateOff } = this.props
let imageObj = {};
if (method === "multer") {
let imageFormObj = new FormData();
imageFormObj.append("imageName", "multer-image-" + Date.now());
imageFormObj.append("imageData", e.target.files[0]);
// stores a readable instance of
// the image being uploaded using multer
this.setState({
multerImage: window.URL.createObjectURL(e.target.files[0])
});
return window.fetch('http://localhost:8016/images/uploadmulter', {
method: 'POST',
// body: e.target.files[0]
body: imageFormObj
})
.then((response) => {
console.log("response ", response);
this.setDefaultImage("multer");
return (
<>
{response.ok && <Modal
isAlertModal={true}
history={history}
affirmativeUsed="Yes"
message="Image has been successfully uploaded!"
isLoggedIn={isLoggedIn}
modalActive={true}
modalStateOn={modalStateOn}
modalStateOff={modalStateOff}></Modal>}
</>
)
})
.then((data) => {
console.log("data ", data);
this.setDefaultImage("multer");
})
.catch(error => {
this.setDefaultImage("multer");
console.log("error ", error);
})
}
} // end upload function
render() {
// console.log("uploadImage function this.props ", this.props);
return (
<div className="main-container">
<h3 className="main-heading">Image Upload App</h3>
<div className="image-container">
<div className="process">
<h4 className="process__heading">Process: Using Multer</h4>
<p className="process__details">Upload image to a node server, connected to a MongoDB database, with the help of multer</p>
<form action="/uploadmulter" method="post" encType="multipart/form-data" >
<input type="file" name="avatar" className="process__upload-btn" onChange={(e) => this.uploadImage(e, "multer")} />
<img src={this.state.multerImage} alt="upload-image" className="process__image" />
</form>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
const { isLoggedIn, modalActive } = state
return { isLoggedIn, modalActive }
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ modalStateOn, modalStateOff }, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(ImageUploader)
And this is the route on my express server server/images/index.js:
var router = require('express').Router();
var Image = require('../models/Image');
var multer = require('multer')
var storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, './server/uploads/');
},
filename: function(req, file, cb){
cb(null, Date.now() + file.originalname)
}
})
var fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
// rejects storing a file
cb(null, false)
}
}
var upload = multer({
storage: storage,
limits : {
fileSize : 1024 * 1024 * 5
},
fileFilter: fileFilter
})
router.route('/uploadmulter')
.post(upload.single('imageData'), (req, res, next) => {
console.log('req.body', req.body);
var newImage = new Image({
imageName: req.body.imageName,
imageData : req.file.path
})
newImage.save()
.then(result => {
res.status(200).json({
success: true,
document:result
})
})
.catch(err=> next(err))
});
module.exports = router
So to reiterate why doesn't the image render and modal fire when the response is true or 200?

Uploading CSV file from react front end to node.js backend and storing it in the folder

I'm trying to upload a file to the backend folder using react's front end form input but I'm unable to do so.
I've added the form, I tried capturing data in the state but for some reason I can't store csv file in a state, is it because of file complexity?
Since I couldn't get the state to store my csv, I used axios to push data straight to the backend which seemed to work but the file was not saved in the backend.
I have 3 files, react App and node Upload
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import CSVReader from 'react-csv-reader';
import axios from 'axios';
class App extends Component {
constructor(props) {
super(props);
this.state = {
apiResponse: '',
file: null,
};
this.handleImport = this.handleImport.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
callAPI() {
fetch("http://localhost:9000/testAPI")
.then(res => res.text())
.then(res => this.setState({ apiResponse: res }));
console.log(this.state.apiResponse)
}
componentDidMount() {
this.callAPI();
}
handleImport(data){
this.setState({file:data.target.files[0]})
//because I couldn't get state to work I used axios imediately with the data
axios.post("http://localhost:9000/upload", data, { // receive two parameter endpoint url ,form data
}).then(res => { // then print response status
console.log(res.statusText)
})
}
//I'm not using handlesubmit here as it involves a button press
handleSubmit(e){
e.preventDefault();
const data = new FormData();
data.append('file', this.state.file);
console.log(data);
axios.post("http://localhost:9000/upload", data, { // receive two parameter endpoint url ,form data
}).then(res => { // then print response status
console.log(res.statusText)
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p className='App-intro'> {this.state.apiResponse}</p>
</header>
<content className='body_cont'>
{/* My Form */}
<form action="POST">
<input type="file" name='file' onChange={this.handleImport} />
<button type='submit' onClick={this.handleSubmit}>Upload File</button>
</form>
</content>
</div>
);
}
}
export default App;
Next file is my upload file for which the routes have been set in app.js
var express = require('express');
var multer = require('multer');
var router = express.Router();
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../folder1/folder2/dm-portal/in')
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' +file.originalname )
}
});
var upload = multer({ storage: storage }).single('file')
router.post('/',function(req, res) {
console.log(req)
upload(req, res, function (err) {
if (err instanceof multer.MulterError) {
return res.status(500).json(err)
} else if (err) {
return res.status(500).json(err)
}
return res.status(200).send(req.file)
})
});
module.exports = router;
End results is I get a whole bunch of warning but the axios seemed to be working, however, the files is not being saved.
Any help appreciated.
P.S. I'm beginner.

Resources