File Upload from API Routes Next.js not working - node.js

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);

Related

File upload with react, nodeJS multer doesn't work

i made this function, which takes the file value ( image ) from the file state and send it to upload route, through FormData object
const [file, setFile] = useState(null);
const submitPost = async (e) => {
...
e.preventDefault();
if (file) {
const data = new FormData();
const fileName = `${Date.now()}${file.name}`;
data.append("name", fileName);
data.append("file", file);
try {
await fetch("http://localhost:8000/upload", {
headers: {
"Content-type": "application/json",
},
method: "POST",
body: JSON.stringify(data),
});
// window.location.reload();
} catch (err) {
console.log(err);
}
}
};
the file value in the file state is coming from form file input
<form className="postOptions" onSubmit={submitPost}>
<div className="postAreaBot">
<label htmlFor="file" className="downloadImg">
<AddAPhotoIcon className="postIcon" />
<span>Image</span>
</label>
<input
type="file"
accept=".png,.jpeg,.jpg"
onChange={(e) => setFile(e.target.files[0])}
id="file"
style={{ display: "none" }}
></input>
</div>
<button type="submit">Post</button>
</form>
and then sending the file value to this route for upload on folder images inside folder public using multer and path
app.use("/images", express.static(path.join(__dirname, "public/images")));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, req.body.name);
},
});
const upload = multer({ storage });
app.post("/upload", upload.single("file"), (req, res) => {
try {
return res.status(200).json("File uploaded successfully");
} catch (err) {
console.log(err);
}
});
but the image is not being uploaded
what have i tried
i tested the route using file.originalName for postman instead of file.req.body and the route does indeed works and images are being uploaded successfully, i also checked the values name and file in the data object and it appends it successfully, i can't see what is the problem, why it doesn't upload the image file through the react fetch request?
Just remove the JSON.stringify. And change your content type, like the example below:
await fetch("http://localhost:8000/upload", {
headers: {
"Content-type": "multipart/form-data",
},
method: "POST",
body: data,
});

Not getting image file in nodejs after posting from react

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');
});
}
...

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.).

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