multer - req.file always undefined - javascript

I've looked at a lot of answer for this same question, but I haven't found a working solution yet. I am trying to make a web app that you can upload files to using express and multer, and I am having a problem that no files are being uploaded and req.file is always undefined.
My code below
'use strict';
var express = require('express');
var path = require('path');
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express();
require('dotenv').load();
app.use(express.static(path.join(__dirname, 'main')));
app.post('/upload', upload.single('upl'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
console.log(req.file);
res.status(204).end();
})
var port = process.env.PORT || 8080;
app.listen(port, function () {
console.log('Node.js listening on port ' + port + '...');
});
The form
<form class="uploadForm" action="/upload" method="post" enctype="multipart/formdata">
<label class="control-label">Select File</label>
<input name="upl" id="input-1" type="file" class="file">
<input type="submit" value="submit" />
</form>
Help very much appreciated, this is driving me crazy.

In case of postman, try following:
Close the postman tab for the API
Open a new tab again
Rebuild the API request and then send.
This may fix the problem. Every time you restart the server you need to do above steps for calling the API again. The reason being multer sends back some cookies called connect.sid to the client which it may require in further communication. Using old cookies will not upload the file.

Your enctype is slightly incorrect, it should be multipart/form-data instead of multipart/formdata.

I put MY (there are many I imagine and surely better) solution to help many people like me because I have searched during 1 entire day ;-(
//JS file on node side
var express = require('express');
var fileUpload = require('express-fileupload');
var fs = require("fs");
var app = express();
console.log('étape 0');
app.use(express.static('mesStatic'));
app.use(fileUpload());
console.log('étape 1');
app.get('/indexFileUpload.htm', function (req, res) {
res.sendFile( __dirname + "/" + "indexFileUpload.htm" );
})
console.log('étape 2');
app.post('/file_upload', function (req, res) {
console.log('étape 3');
console.log('req.files:' , req.files);
if (!req.files) {
res.send('No files to upload.');
return;
}
console.log('req.files.file.data:' , req.files.file.data);
var bufDataFile = new Buffer(req.files.file.data, "utf-8");
console.log('étape 3.1');
console.log('__dirname : ' + __dirname);
fs.writeFile(__dirname + '/file_upload/output.txt', bufDataFile, function(err) {
if (err) {
return console.error(err);
}
else {
console.log("Data written successfully !");
}
console.log('étape 4');
res.end('Fin OK !!!');
})
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port);
})

Yes, your enctype is wrong and that is the only problem. Make sure that you correct your enctype otherwise you are likely to get undefined in req.file or req.files.

Hello Guys I have also wasted 24 hours and was getting same error i.e req.file is undefined. Now you can refer below code to check your solution. This is single file demo code for uploading file using multer in Node and postman. In POSTMAN Select POST method and select form-data and Key name should be 'profile'.
var express = require('express');
const app = express();
const port = 3000;
var multer = require('multer');
var upload = multer({dest:'uploads/'});
var storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, './uploads');
},
filename: function (req, file, cb) {
cb(null , file.originalname);
}
});
var upload = multer({ storage: storage })
app.post('/single', upload.single('profile'), (req, res, error) => {
try {
console.log(req.file);
res.send(req.file);
}catch(err) {
res.send(400);
}
});
app.get('/', (req, res) => {
res.send('hello Guys');
});
app.listen(port, () => {
console.log('listening to the port: ' + port);
});

If you are using error handling as mentioned in the document, then req.file will be undefined.
An alternative way to use both error handling and to check if the file exists is to make use of express error handling:
index.js
const express = require("express");
const bodyParser = require("body-parser");
const upload = require("./upload");
const multer = require("multer");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.get("/", function (req, res) {
res.send("Hello World");
});
app.post("/upload_file", upload.single("file"), function (req, res) {
if (!req.file) {
throw Error("FILE_MISSING");
} else {
res.send("success");
}
});
//Express Error Handling
app.use(function (err, req, res, next) {
if (err instanceof multer.MulterError) {
res.statusCode = 400;
res.send(err.code);
} else if (err) {
if (err.message === "FILE_MISSING") {
res.statusCode = 400;
res.send("FILE_MISSING");
} else {
res.statusCode = 500;
res.send("GENERIC_ERROR");
}
}
});
const server = app.listen(8081, function () {
const port = server.address().port;
console.log("App started at http://localhost:%s", port);
});
upload.js
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 upload = multer({
storage: storage,
// limits: { fileSize: 10 },
});
module.exports = upload;

HTML File,
<form class="uploadForm" action="/upload" method="post" enctype="multipart/form-data">
<label class="control-label">Select File</label>
<input name="upl" id="input-1" type="file" class="file">
<input type="submit" value="submit" />
</form>
app.js
var express=require("express");
var multer=require("multer");
var app=express();
var upload=multer({dest:"uploads/"});
app.post("/upload",upload.single("upl"),function(req,res){
console.log("Uploaded Successfull with filename : "+req.upl.filename);
});

For us this was because we were using express-http-proxy to proxy the call before multer, and we needed to use the parseReqBody: false option to properly send over the file.
ie.
app.post('file/upload', proxy(process.env.API_URL, {
parseReqBody: false,
}))

Use:
formdata.append('file',document.getElementById("input-file").files[0]);
Instead of:
formdata.append('file',document.getElementById("input-file").files);
This is where I have done the mistake.

1- Add the below lines in your server.js or index.js root file
app.use(express.json());
app.use(express.urlencoded({
extended: true,
})
);
2- Create a folder name middleware and inside it create a file name
upload.js.
3- Place the following code in upload.js file
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/");
},
filename: function (req, file, cb) {
const imgName = file.originalname;
cb(null, imgName );
},
});
const upload = multer({
storage: storage,
});
module.exports = upload;
4- Add this middleware in any route. For example:
const upload = require("../middlewares/fileUpload");
router.route("/send").post(upload.single("profile"),
((req,res) => {
*your controller logic here*
});
**Note: Here profile is the name of the key of image or file that you are sending**

having a similar issue with req.file being undefined. It looks like the image file is available up until the hook useFormSubmit wraps it in the formData object and sends the formData request to the router/controller.
However even just sending the image using the body, nothing comes through from the hook to the controller. I've included images of the console logs for the status of the data from the component to the controller below, would appreciate any guidance on this:
Things I've tried:
-Sending the form in incognito to avoid cookies or caching
-Sending reviewImage data in the body itself without wrapping it in formData.append
-including the multer middleWare directly in the router and controller
-pulling the image from req.body instead of req.file
CreateReview.tsx
//hooks
import {useFormSubmit} from '../../Hooks/useFormSubmit'
//dependencies
import { useForm, SubmitHandler } from "react-hook-form";
export const CreateReview = () => {
const { register, handleSubmit, formState: { errors } } = useForm<ReviewInputs>();
const {createReview, error, isLoading} = useFormSubmit()
const onSubmit: SubmitHandler<ReviewInputs> = async (data) => {
const userID = user
const title: string = data.title
const review: string = data.review
const artist: string = data.artist
const author: string = data.author
const authorBand: string = data.authorBand
const banner: string = data.banner
const reviewImage: any = data.reviewImage[0]
await createReview(title, review, artist, userID, author, authorBand, banner, reviewImage)
navigate('/adminReviews')
}
return (
<>
<Form onSubmit={handleSubmit(onSubmit)} encType="multipart/form-data">
<Form.Label>Create A Review</Form.Label>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Title" {...register('title', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Artist</Form.Label>
<Form.Control type="text" placeholder="Artist" {...register('artist', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Author</Form.Label>
<Form.Control type="text" placeholder="Author" {...register('author', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Author Band</Form.Label>
<Form.Control type="text" placeholder="Author Band" {...register('authorBand', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Upload An Image</Form.Label>
<Form.Control type="file" placeholder="Upload" {...register('reviewImage', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Banner</Form.Label>
<Form.Control type="text" placeholder="Banner" {...register('banner', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Review</Form.Label>
<Form.Control as="textarea" rows={12} {...register('review', {required: true })} {...register} />
<>{errors.review?.message}</>
</Form.Group>
<Row>
<Col xs={12}>
<Button type='submit'>Submit</Button>
</Col>
</Row>
</Form>
useFormSubmit
export const useFormSubmit = () => {
const {dispatch} = useReviewsContext()
const [error, setError] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const createReview = async (title, review, artist, userID, author, authorBand, banner, reviewImage) => {
const formData = new FormData();
formData.append("reviewImage", reviewImage);
setIsLoading(true)
setError(null)
const response = await fetch('http://localhost:8080/api/admin/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title, review, artist, userID, author, authorBand, banner, formData })
})
const jsonResponse = await response.json()
if(!response.ok) {
setIsLoading(false)
setError(jsonResponse.error)
}
if(response.ok) {
setIsLoading(false)
dispatch({type: 'CREATE_REVIEW', payload: jsonResponse})
}
}
adminMiddleware.js
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, '../../client/public/images')
},
filename: (req, file, callback) => {
callback(null, file.originalname)
}
})
const upload = multer({storage: storage})
module.exports = upload;
adminRoutes.js
const express = require('express')
const router = express.Router();
const upload = require('../middleware/adminMiddleware')
//controllers
const { createReview } = require('../controllers/reviewsController')
//CRUD reviews routes
router.post('/', upload.single('reviewImage'), createReview)
module.exports = router;
reviewsController.js
const createReview = async (req, res) => {
const {title, review, artist, userID, author, authorBand, banner} = req.body
const reviewImage = req.file.reviewImage
let emptyFields = []
if(!title) {
emptyFields.push('title')
}
if(!review) {
emptyFields.push('review')
}
if(!artist) {
emptyFields.push('artist')
}
if(!userID) {
emptyFields.push('userID')
}
if(!author) {
emptyFields.push('author')
}
if(!authorBand) {
emptyFields.push('authorBand')
}
if(!banner) {
emptyFields.push('banner')
}
if(!reviewImage) {
emptyFields.push('reviewImage')
}
if(emptyFields.length > 0) {
return res.status(400).json({ error: 'Please fill in all the fields', emptyFields })
}
// add doc to db
try {
const createdReview = await Review.create({title, review, artist, userID, author, authorBand, banner, reviewImage})
res.status(200).json(createdReview)
} catch (error) {
res.status(400).json({error: error.message})
}
}
Error Messages / Console logs

Related

No such file or directory, lstat \async hooks required by \node_modules\on-finished\index.js

I am trying to figure out what I have done wrong with this Javascript code. I have tried googling the error with no avail.
The following is there error I get.
Error: Can't walk dependency graph: ENOENT: no such file or directory, lstat 'C:\Users\calon\source\repos\CAL0NZ0\Treasure-Box-Azure\async_hooks'
required by C:\Users\calon\source\repos\CAL0NZ0\Treasure-Box-Azure\node_modules\on-finished\index.js
And here is the Javascript code used.
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const { CosmosClient } = require('#azure/cosmos');
const config = require('./config');
const endpoint = config.endpoint;
const key = config.key;
const client = new CosmosClient({ endpoint, key });
const database = client.database('treasure_box');
const container = database.container('logins');
const app = express();
let initialPath = path.join(__dirname, 'treasure-box-azure');
app.use(bodyParser.json());
app.use(express.static(initialPath));
app.get('/', (req, res) => {
res.sendFile(path.join(initialPath, 'index.html'));
});
app.get('/login', (req, res) => {
res.sendFile(path.join(initialPath, 'login.html'));
});
app.get('/register', (req, res) => {
res.sendFile(path.join(initialPath, 'register.html'));
});
app.post('/register-user', (req, res) => {
const { name, email, password } = req.body;
if (!name.length || !email.length || !password.length) {
res.json('Fill out all field');
} else {
container
.insert({
name: name,
email: email,
password: password,
})
.returning(['name', 'email'])
.then((data) => {
res.json(data[0]);
})
.catch((err) => {
if (err.detail.includes('Already Exists')) {
res.json('Email already exists');
}
});
}
});
app.post('/login-user', (req, res) => {
const { email, password } = req.body;
container
.select('name', 'email')
.where({
email: email,
password: password,
})
.then((data) => {
if (data.length) {
res.json(data[0]);
} else {
res.json('Email or password is incorrect');
}
});
});
app.listen(403, (req, res) => {
console.log('listening on 403');
});
I use the following command to allow my JS files to run on the browser. I don't have any issues with the other files. Just this particular one.
"browserify ./application/staging/index-s.js > ./application/deploy/index.js -t babelify --plugin tinyify"

File upload makes Node JS unresponsive with Multer

I am using Multer Node JS package to upload files to my app sever , the code is basically typical upload file code
const express = require('express')
const multer = require('multer')
const upload = multer({ dest: 'uploads/' })
const app = express()
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
But each time a file is being uploaded the Node server becomes unresponsive and frontend from other request doesnt receive any response from other APIs until the file is uploaded.
Whats the best way to tackle this ?
In your sample code, you must just send a response to the client by res.json() or res.end() :
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
const app = express();
app.post('/profile', upload.single('avatar'), function (req, res, next) {
// req.file is the `avatar` file
// req.body will hold the text fields, if there were any
res.status(204).end();
});
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
res.status(204).end();
});
i can give you an example of how i implemented an imageupload in my app. it the code to upload a profile image for a user. i am also using multer middleware so it shoulder be similiar for you:
code is as follows:
// multer middleware:
const multer = require('multer');
const MIME_TYPE_MAP = {
'image/png': 'png',
'image/jpeg': 'jpg',
'image/jpg': 'jpg',
};
module.exports = storage = multer.diskStorage({
destination: (req, file, cb) => {
const isValid = MIME_TYPE_MAP[file.mimetype];
let error = new Error('invalid mime type');
if (isValid) {
error = null;
}
cb(error, 'images');
},
filename: (req, file, cb) => {
const name = file.originalname.toLowerCase().split(' ').join('-');
const ext = MIME_TYPE_MAP[file.mimetype];
if (name.includes('.' + ext)) {
cb(null, name)
} else {
cb(null, name + '.' + ext);
}
},
});
and here the code in the service handling the fileupload
// profile service in backend written in express
exports.uploadImage = (req, res, next) => {
const url = req.protocol + '://' + req.get('host');
profileRepository
.findOne({ _id: req.params.id })
.then((response) => {
const fetchedUser = response;
fetchedUser.imagePath = url + '/images/' + req.file.filename;
profileRepository
.updateOne({ _id: req.params.id }, fetchedUser)
.then((response) => {
return res.status(200).json({
message: 'profileimage updated',
});
})
.catch((error) => {
return res.status(500).json({
message: 'uploading image failed',
});
});
})
.catch((error) => {
return res.status(404).json({
message: 'fetching user failed',
});
});
};
then i use the middleware in my profile routes file like this:
// profile.routes.js
const express = require('express');
const ProfileController = require('./profileController');
const checkAuth = require('../middleware/checkAuth');
const router = express.Router();
const fileStorage = require('../middleware/fileStorage');
const multer = require('multer');
// imageUpload
router.post('/user/image/:id', checkAuth, multer({storage: fileStorage}).single('image'), ProfileController.image);
my Controller then calls the service function with the actual business logic like this:
// profile.controller.js
const profileService = require('./profileService');
exports.image = (req, res, next) => {
return profileService.uploadImage(req, res);
};
and finally my route is used by my app.js file like this:
// app.js
const express = require('express');
const profileRoutes = require('./profile/profileRoutes');
const app = express();
// set images path for saving images on server
app.use('/images', express.static(path.join('images')));
app.use('/api', profileRoutes);
module.exports = app;
i hope i was able to point you in the right direction with my example

Using React.js, Node.js and Multer, how can I console log 'req.file' on the server?

I am building a MERN app and when I try to console.log(req.file) on the server I get undefined. I've checked the multer github page and other SO articles, but I still haven't been able to figure it out using React hooks and jsx. I'm newish to SO so, I will add edits since I can't comment yet.
Here is a link to the branch in GitHub if you want to see all the files. https://github.com/BenjDG/puzzle-gallery/tree/so
I'm new to multer and react so any help is appreciated.
Here is my code:
server\controllers\puzzleController.js
const multer = require('multer');
const upload = multer({ dest: './uploads'});
const db = require('../models');
const fs = require('fs');
const type = upload.single('picFile');
// Defining methods for the puzzleController
module.exports = {
findAll: function (req, res) {
db.Puzzle
.find(req.query)
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
save: (type, function (req, res) {
// console.log(req);
console.log(req.file);
console.log(req.body);
res.sendStatus(200);
}),
remove: function (req, res) {
db.Puzzle
.findById({ _id: req.params.id })
.then(dbModel => dbModel.remove())
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
}
};
client\src\components\gallery\index.js
import React, { useState } from 'react';
import './styles.css';
import API from '../../services/API';
export default function Gallery () {
const [picFile, setPicFile] = useState();
const handleGetClick = async () => {
API.findAll()
.then(res => {
console.log(res)
})
.catch(err => console.error(err))
}
const handleUploadClick = async (e) => {
e.preventDefault();
// console.log(picFile);
// create new formData instance
const bodyFormData = new FormData();
// append single file to formData instance
bodyFormData.append('picFile', picFile.selectedFile);
// log items in formData object
for (const element of bodyFormData) {
console.log(element);
}
// send formData obj to axios function
API.save(bodyFormData)
.then(res => {
//console.log(res)
})
.catch(err => console.error(err))
}
const onFileChange = (e) => {
console.log(`e.target.files[0]`, e.target.files[0])
setPicFile({ selectedFile: e.target.files[0] });
}
return (
<div>
<h1>My Puzzle Gallery</h1>
<form encType='multipart/form-data'>
<input type='file' name='picFile' onChange={onFileChange} />
<br />
<br />
<button onClick={handleUploadClick}>Upload a picture</button>
</form>
<br />
<br />
<button onClick={handleGetClick}>Get pictures</button>
<br />
<br />
<img src='https://placekitten.com/640/360' alt='kitten' />
</div>
);
}
client\src\services\API.js
import axios from 'axios';
const API = {
login: (username, password) => {
const obj = {
username: username,
password: password
};
return axios.post('/api/auth/login', obj);
},
register: (username, password) => {
const obj = {
username: username,
password: password
};
return axios.post('/api/auth/register', obj);
},
logout: function () {
return axios.get('api/auth/logout');
},
save: function (form) {
return axios.post('api/puzzle/', form).catch(err=>console.error(err));
},
findAll: function () {
return axios.get('api/puzzle/');
},
}
export default API;
server\routes\api\puzzle\index.js
const router = require('express').Router();
const puzzleController = require('../../../controllers/puzzleController');
// Matches with '/api/puzzle'
router.route('/')
.get(puzzleController.findAll)
.post(puzzleController.save);
// Matches with '/api/books/:id'
router.route('/delete/:id')
.delete(puzzleController.remove);
module.exports = router;
server\server.js
const path = require('path');
const express = require('express');
const passport = require('./config/passport');
const mongoose = require('mongoose');
const cors = require('cors');
const session = require('express-session');
const helmet = require('helmet');
const morgan = require('morgan');
const corsOptions = require('./config/cors.js');
const routes = require('./routes');
const { v1: uuidv1 } = require('uuid');
// console.log(uuidv1());
const PORT = process.env.PORT || 3001;
const app = express();
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/puzzlegallery', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
useFindAndModify: false
});
mongoose.set("useCreateIndex", true);
// Define middleware here
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(helmet({ contentSecurityPolicy: false }));
app.use(session({ secret: 'sassy', resave: false, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use(cors(corsOptions));
app.use(morgan('dev'));
app.use(routes);
// for Reactjs ##################
// Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
}
// #################################################
if (process.env.NODE_ENV === 'production') {
app.get('*', (_, res) => {
res.sendFile(path.join(__dirname, '../client/build/index.html'));
});
}
app.listen(PORT, (err) => {
if (err) throw err;
console.log(
`🌎 Server is Ready and Listening on http://localhost:${PORT}`
); // eslint-disable-line no-console
});
EDIT:
This seemed to work. Thanks again!!
const path = require('path');
const router = require('express').Router();
const puzzleController = require('../../../controllers/puzzleController');
const multer = require('multer');
const { v1: uuidv1 } = require('uuid');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, '../../../../tmp/my-uploads'))
},
filename: function (req, file, cb) {
cb(null, uuidv1())
}
})
const upload = multer({ storage: storage });
// Matches with '/api/puzzle'
router.route('/')
.get(puzzleController.findAll)
// Matches with '/api/books/:id'
router.route('/delete/:id')
.delete(puzzleController.remove);
router.use(upload.single('picFile'));
router.route('/')
.post(puzzleController.save);
module.exports = router;
you cannot call the middleware inside the save function like this.
I cloned your repo and added the following code in server.js and it's working fine and I got the value in the req.file.
const multer = require('multer');
const upload = multer({ dest: 'uploads/'});
app.post('/api/puzzle/', upload.single('pictureFile'),(req,res,next)=>{
console.log("req.file22222222", req.file);
})

Not getting form data in req.body Express/node.js

I am trying to create e registration for a new user with profile picture upload. But my form data is not passing to the route. I have added body-parser middleware but still, it seems something is wrong and I cannot find the reason.
Error:
D:\temp_project\smpms\routes\users.js:118
if (err) throw err;
^
Error: Illegal arguments: undefined, string
at _async (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:214:46)
at Object.bcrypt.hash (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:220:13)
at D:\temp_project\smpms\routes\users.js:117:28
at Immediate.<anonymous> (D:\temp_project\smpms\node_modules\bcryptjs\dist\bcrypt.js:153:21)
at processImmediate (internal/timers.js:456:21)
[nodemon] app crashed - waiting for file changes before starting...
app.js
const express = require("express");
const expressLayouts = require("express-ejs-layouts");
const mongoose = require("mongoose");
const passport = require("passport");
const flash = require("connect-flash");
const session = require("express-session");
const multer = require('multer');
const path = require('path');
var dotenv = require('dotenv').config();
const bodyParser = require('body-parser');
const app = express();
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(express.static("public"));
// Passport Config
require("./config/passport")(passport);
// DB Config
const db = require("./config/keys").mongoURI;
// Connect to MongoDB
mongoose
.connect(db, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => console.log("MongoDB Connected"))
.catch((err) => console.log(err));
// EJS
app.use(expressLayouts);
app.set("view engine", "ejs");
// Express body parser
app.use(express.urlencoded({ extended: true }));
// Express session
app.use(
session({
secret: "secret",
resave: true,
saveUninitialized: true,
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function (req, res, next) {
res.locals.success_msg = req.flash("success_msg");
res.locals.error_msg = req.flash("error_msg");
res.locals.error = req.flash("error");
next();
});
// Routes
app.use("/", require("./routes/index.js"));
app.use("/users", require("./routes/users.js"));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
User.js - User model
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar:{
type:String,
required:true
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('User', UserSchema);
module.exports = User;
User.js route:
const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
const passport = require("passport");
const multer = require('multer');
const path = require('path');
const bodyParser = require('body-parser')
const app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// Load User model
const User = require("../models/User");
const {forwardAuthenticated} = require("../config/auth");
// Login Page
router.get("/login", forwardAuthenticated, (req, res) => {
res.render("login", {title: "Login", layout: "layout"});
});
// Register Page
router.get("/register", forwardAuthenticated, (req, res) => {
res.render("register", {title: "Register", layout: "layout"});
});
// Register
router.post("/register", (req, res) => {
//const {name, email, password, password2||avatar} = req.body;
const name = req.body.name
const email = req.body.email
const password = req.body.password;
const password2 = req.body.password2;
const avatar = req.body.avatar;
let errors = [];
//
// if (!name || !email || !password || !password2) {
// errors.push({msg: "Please enter all fields"});
// }
// if (password && password.length < 6) {
// errors.push({msg: "Password must be at least 6 characters"});
// }
// if (password != password2) {
// errors.push({msg: "Passwords do not match"});
// }
if (errors.length > 0) {
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
User.findOne({email: email}).then((user) => {
if (user) {
errors.push({msg: "Email already exists"});
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
const newUser = new User({
name,
email,
password,
});
//Set The Storage Engine
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + newUser._id + path.extname(file.originalname));
}
});
// Init Upload
const upload = multer({
storage: storage,
limits: {fileSize: 1000000},
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
}).single('avatar');
// Check File Type
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Images Only!');
}
}
console.log(newUser);
newUser.avatar = storage;
console.log(newUser);
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then((user) => {
req.flash(
"success_msg",
"You are now registered and can log in"
);
res.redirect("/users/login");
})
.catch((err) => console.log(err));
});
});
}
});
}
});
// Login
router.post("/login", (req, res, next) => {
passport.authenticate("local", {
successRedirect: "/dashboard",
failureRedirect: "/users/login",
failureFlash: true,
})(req, res, next);
});
// Logout
router.get("/logout", (req, res) => {
req.logout();
req.flash("success_msg", "You are logged out");
res.redirect("/users/login");
});
module.exports = router;
Register.ejs is the file where the form is not passing data to the route.
<div class="row mt-5">
<div class="col-md-6 m-auto">
<div class="card card-body">
<h1 class="text-center mb-3">
<i class="fas fa-user-plus"></i> Register
</h1>
<% include ./partials/messages %>
<%= typeof msg != 'undefined' ? msg : '' %>
<form action="/users/register" method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="name">Name</label>
<input
type="name"
id="name"
name="name"
class="form-control"
placeholder="Enter Name"
value="<%= typeof name != 'undefined' ? name : '' %>"
/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
class="form-control"
placeholder="Enter Email"
value="<%= typeof email != 'undefined' ? email : '' %>"
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
name="password"
class="form-control"
placeholder="Create Password"
value="<%= typeof password != 'undefined' ? password : '' %>"
/>
</div>
<div class="form-group">
<label for="password2">Confirm Password</label>
<input
type="password"
id="password2"
name="password2"
class="form-control"
placeholder="Confirm Password"
value="<%= typeof password2 != 'undefined' ? password2 : '' %>"
/>
</div>
<div class="form-group">
<label for="">Profile Picture</label>
<input type="file" name="avatar" id="" class="form-control file-path validate">
</div>
<button type="submit" class="btn btn-primary btn-block">
Register
</button>
</form>
<p class="lead mt-4">Have An Account? Login</p>
</div>
</div>
</div>
It seems that you aren't using multer correctly. Usually multer configuration is set globally and above all the APIs and then we pass that middleware function generated by multer to that specific API which has multipart/form-data header in its request. You have to move your configuration for multer, outside of your API, then pass the upload as a middleware to your API. Also from your clientside, you have to pass data properly. A good answer about sending JSON alongside the File with FormData object can be found here. Also you can add text fields in FormData object from clientside and receive it as object in req.body according to multer documentation. Just make sure you're passing data from clientside to server correctly. Here is your router with multer middleware:
const express = require("express");
const router = express.Router();
const fs = require('fs');
const bcrypt = require("bcryptjs");
const passport = require("passport");
const multer = require('multer');
const path = require('path');
const bodyParser = require('body-parser')
const app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
// Load User model
const User = require("../models/User");
const { forwardAuthenticated } = require("../config/auth");
// Login Page
router.get("/login", forwardAuthenticated, (req, res) => {
res.render("login", { title: "Login", layout: "layout" });
});
// Register Page
router.get("/register", forwardAuthenticated, (req, res) => {
res.render("register", { title: "Register", layout: "layout" });
});
const storage = multer.diskStorage({
destination: './public/uploads/'
});
// Init Upload
const upload = multer({
storage: storage,
limits: { fileSize: 1000000 },
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
});
// Check File Type
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Images Only!');
}
}
// Register
router.post("/register", upload.single('avatar'), (req, res) => {
//const {name, email, password, password2||avatar} = req.body;
const name = req.body.name
const email = req.body.email
const password = req.body.password;
const password2 = req.body.password2;
let errors = [];
//
// if (!name || !email || !password || !password2) {
// errors.push({msg: "Please enter all fields"});
// }
// if (password && password.length < 6) {
// errors.push({msg: "Password must be at least 6 characters"});
// }
// if (password != password2) {
// errors.push({msg: "Passwords do not match"});
// }
if (errors.length > 0) {
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
User.findOne({ email: email }).then((user) => {
if (user) {
errors.push({ msg: "Email already exists" });
res.render("register", {
errors,
name,
email,
password,
password2,
title: "Register",
layout: "Layout",
});
} else {
const directory = "/images/";
const newUser = new User({
name,
email,
password,
avatar: `./public/uploads/${req.file}`
});
const filePath = path.join(__dirname, "../public/uploads/");
fs.rename(filePath + req.file.filename, req.file.fieldname + '-' + newUser._id + path.extname(req.file.originalname), (error) => {
if (error) {
return console.log(`Error: ${error}`);
}
});
newUser.avatar = 'public/uploads/' + req.file.fieldname + '-' + newUser._id + path.extname(req.file.originalname);
console.log(newUser);
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then((user) => {
req.flash(
"success_msg",
"You are now registered and can log in"
);
res.redirect("/users/login");
})
.catch((err) => console.log(err));
});
});
}
});
}
});
// Login
router.post("/login", (req, res, next) => {
passport.authenticate("local", {
successRedirect: "/dashboard",
failureRedirect: "/users/login",
failureFlash: true,
})(req, res, next);
});
// Logout
router.get("/logout", (req, res) => {
req.logout();
req.flash("success_msg", "You are logged out");
res.redirect("/users/login");
});
module.exports = router;
It will save your file without any problem (if your configuration about directory and filename was okay).

How can I access the body of the request from this middleware?

I'm trying to access the body of the request in a middleware in order to perform it only if a specific field has changed (ereasing pictures only if new pictures got uploaded), but I'm not able to access the body.
I've tried to install and configure cors as well as reconfiguring body-parser in the route-specific file, as well as shuffling around the code, but nothing has helped (this is what was suggested in other questions).
const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const multer = require('multer');
const glob = require('glob');
const fs = require('fs');
const _ = require('lodash');
const urlencodedParser = bodyParser.urlencoded({ extended: false });
//MIDDLEWARE
router.use("/immobili/:_id/edit", urlencodedParser, function (req, res, next) {
console.log(req.body);
const requestedId = req.params._id;
Immobile.findOne({ _id: requestedId }, (err, immobile) => {
if (err) return console.error(err);
immobile.immagini = [];
cancellaFoto(immobile);
if (this.cancellato) {
return setTimeout(next, 1000);
} else {
return console.log("Aborted");
}
});
});
//EDIT PUT ROUTE
router.put("/immobili/:_id/edit", upload.array('immaginePrincipale', 30), function (req, res) {
const requestedId = req.params._id;
const dati = req.body;
const proprietaImmagini = req.files;
const immagini = proprietaImmagini.map(function (immagine) {
//console.log(immagine.path);
return immagine.path;
});
let vetrina;
req.body.vetrina === 'on' ? vetrina = true : vetrina = false;
Immobile.findOneAndUpdate({ _id: requestedId }, {
numeroScheda: dati.numeroScheda,
//[... ALL DATA ... ]
immagini: immagini,
}, function (err, updatedImmobile) {
if (err) return console.error(err);
res.redirect("/immobili/" + req.body.categoria + "/" + _.toLower(req.body.localita) + "/" + requestedId);
});
});
This is the form I'm using to send the data:
<form action="/immobili/<%= immobile._id %>/edit?_method=PUT" method="POST"
enctype="multipart/form-data">
//[ ... FORM INPUTS ... ]
<input type="file" name="immaginePrincipale" multiple="multiple" id="immaginePrincipale"></input>
<input type="submit" value="Pubblica">
</form>
I would expect to access the body of the request in the middleware but I get only an empty object in return.

Categories

Resources