NodeJS application doesn't upload files - node.js

I am developing a very simple JavaScript application with NodeJS. Simply upload files and view their content by paragraphs.
The problem is that every time I upload a file, I get the error "No files were uploaded." which corresponds to the following lines:
app.post('/upload_file', (req, res) => {
if (!req.files || !req.files.filetoupload) {
return res.status(400).send('No files were uploaded.');
}
[...]
}
This is the complete code:
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const fs = require('fs');
const sqlite3 = require('sqlite3').verbose();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
if (!fs.existsSync('./db')) {
fs.mkdirSync('./db');
}
if (!fs.existsSync('./uploads')) {
fs.mkdirSync('./uploads');
}
let db = new sqlite3.Database('./db/paragraphs.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to the paragraphs database.');
});
db.run('CREATE TABLE IF NOT EXISTS paragraphs (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, tag TEXT)', (err) => {
if (err) {
console.error(err.message);
}
console.log('Created paragraphs table.');
});
app.get('/', (req, res) => {
res.send('<h1>Hello World!</h1>' +
'<meta charset="utf-8">' +
'Upload File<br>' +
'Visualize Paragraphs<br>' +
'Tag Paragraphs');
});
app.get('/file_uploading', (req, res) => {
res.send('<h1>File Uploading</h1>' +
'<meta charset="utf-8">' +
'<form action="/upload_file" method="post" enctype="multipart/form-data">' +
'<input type="file" name="filetoupload"><br>' +
'<input type="submit">' +
'</form>');
});
app.post('/upload_file', (req, res) => {
if (!req.files || !req.files.filetoupload) {
return res.status(400).send('No files were uploaded.');
}
let file = req.files.filetoupload;
let filename = file.name;
fs.writeFile('./uploads/' + filename, data, (err) => {
if (err) {
return console.log(err.message);
}
console.log('The file has been saved!');
});
file.mv('./uploads/' + filename, (err) => {
if (err) {
return res.status(500).send(err);
}
res.send('File uploaded!<br>' +
'Upload Another File<br>' +
'Visualize Paragraphs<br>' +
'Tag Paragraphs');
});
fs.readFile('./uploads/' + filename, {encoding: 'utf-8'}, (err, data) => {
if (err) {
return console.log(err.message);
}
let lines = data.split('\n');
for (let i = 0; i < lines.length; i++) {
db.run('INSERT INTO paragraphs (text) VALUES (?)', [lines[i]], (err) => {
if (err) {
return console.log(err.message);
}
});
}
});
});
app.get('/visualize_paragraphs', (req, res) => {
db.all('SELECT * FROM paragraphs', (err, rows) => {
if (err) {
throw err;
}
rows.forEach((row) => {
res.write('<h1>Visualize Paragraphs</h1>');
res.write(row.text + '<br>');
});
res.end();
});
});
app.get('/tag_paragraphs', (req, res) => {
let paragraph_id = req.query.paragraph_id;
let tag = req.query.tag;
if (paragraph_id && tag) {
db.run('UPDATE paragraphs SET tag = ? WHERE id = ?', [tag, paragraph_id], function (err) {
if (err) {
return console.log(err.message);
}
console.log(`Row(s) updated: ${this.changes}`);
});
res.send('<h1>Tag Paragraphs</h1>' +
'<p>Paragraph ' + paragraph_id + ' has been tagged as ' + tag + '</p>');
} else {
db.all('SELECT * FROM paragraphs', (err, rows) => {
if (err) {
throw err;
}
res.write('<h1>Tag Paragraphs</h1>' +
'<table>');
rows.forEach((row) => {
res.write('<tr><td>' + row.id + '</td><td>' + row.text + '</td></tr>');
});
res.write('</table>' +
'<form action="/tag_paragraphs" method="get">' +
'<label for="paragraph_id">Paragraph ID:</label>' +
'<input type="text" id="paragraph_id" name="paragraph_id"><br>' +
'<label for="tag">Tag:</label>' +
'<input type="text" id="tag" name="tag"><br>' +
'<input type="submit" value="Submit">' +
'</form>');
res.end();
});
}
});
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});
Can you help me? What am I doing wrong?

Try uploading file using Multer Middle ware it will ease out your life, I am attaching a sample code which I used in one of my Project
const express = require('express');
const fs = require('fs');
const Log = require('../utils/Log');
const User = require('../db/models/user_model');
const BandCode = require('../db/models/band_codes')
const UserRouter = new express.Router();
const Response = require('../const/Response');
const auth = require('../middleware/auth');
const path = require('path');
const multer = require('multer')
const sharp = require('sharp')
const appleReceiptVerify = require('node-apple-receipt-verify');
const validator = require('validator');
const { sendPasswordResetEmail } = require('../emails/account');
const { totp } = require('otplib');
const { isError } = require('util');
const key = process.env.TOTP;
totp.options = { step: 1800 }
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, process.env.PUBLIC)
},
filename: (req, file, cb) => {
cb(null, req.user._id + '' + Date.now() + path.extname(file.originalname))
}
});
const upload = multer({
storage,
limits: {
fileSize: 9000000
},
fileFilter(req, file, cb) {
if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
return cb(new Error('Please upload an image'))
}
cb(undefined, true)
}
})
UserRouter.post('/users/avatar', auth, upload.single('avatar'), async (req, res) => {
console.log("User Image Update Request")
const filepath = process.env.BASE_PATH +req.file.filename;
console.log(filepath)
req.user.imageUrl = filepath;
req.user.avatar = null
// const file = await sharp(req.file.buffer).resize({ width: 250, height: 250 }).png().toFile();
// req.user.avatar = buffer
await req.user.save()
const user = req.user.toObject();
delete user.avatar
delete user.password
delete user.token
delete user.tokens
delete user.socialId
delete user.totop
delete user.buffer
delete user.__v
const response = new Response("SUCCESS", "Image saved", 200, 0, { user });
res.send(response)
}, (error, req, res, next) => {
console.log(error);
res.status(400).send({ error: error.message })
})
module.exports = UserRouter;

From the documentation:
In Express 4, req.files is no longer available on the req object by default. To access uploaded files on the req.files object, use multipart-handling middleware like busboy, multer, formidable, multiparty, connect-multiparty, or pez.
… and you don't have any such middleware loaded.

Ah, I have had the problem before.
It's probably the form type that's being sent by the client.
I would look into multer!
https://www.npmjs.com/package/multer
I think you'll find your solution with that package

you have to use multer for file upload
router.post('/upload-file', upload.single('image'))
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().toString()}-${file.originalname}`);
}
});
const upload = multer({ storage: storage, limits: { fieldSize: 10 * 1024 * 1024 } });

Answer extracted from question, added in behalf of the asker
This is the solution and the fixed code.
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const fs = require('fs');
const sqlite3 = require('sqlite3').verbose();
const multer = require('multer');
const path = require('path');
// Set up multer
const storage = multer.diskStorage({
destination: './uploads/',
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
},
});
const upload = multer({
storage,
dest: './uploads/',
limits: {
fileSize: 1000000
},
fileFilter: function (req, file, cb) {
checkFileType(file, cb);
}
});
// Check if the file is a txt file
function checkFileType(file, cb) {
const filetypes = /\.(txt)$/;
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
const mimetypes = 'text/plain'
mimetype = mimetypes === file.mimetype;
if (mimetype && extname) {
return cb(null, true);
} else {
cb('Error: Only txt files are allowed!');
}
}
// Set up express
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
// Create directories if they don't exist
if (!fs.existsSync('./db')) {
fs.mkdirSync('./db');
}
if (!fs.existsSync('./uploads')) {
fs.mkdirSync('./uploads');
}
// Connect to the database
let db = new sqlite3.Database('./db/paragraphs.db', sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE, (err) => {
if (err) {
console.error(err.message);
}
console.log('Connected to the paragraphs database.');
});
// Create the paragraphs table if it doesn't exist
db.run('CREATE TABLE IF NOT EXISTS paragraphs (id INTEGER PRIMARY KEY AUTOINCREMENT, text TEXT, tag TEXT)', (err) => {
if (err) {
console.error(err.message);
}
console.log('Created paragraphs table.');
});
// Home page
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
/*
res.write('<h1>Welcome to the Paragraphs App</h1>' +
'Upload a File<br>' +
'Visualize Paragraphs<br>' +
'Tag Paragraphs');
res.end();
*/
});
app.get('/file_uploading', (req, res) => {
res.sendFile(__dirname + '/file_uploading.html');
});
app.post('/upload_file', upload.single('filetoupload'), async (req, res) => {
let filename = req.file.filename;
res.send('File uploaded!<br>' +
'Upload Another File<br>' +
'Visualize Paragraphs<br>' +
'Tag Paragraphs');
fs.readFile('./uploads/' + filename, {encoding: 'utf-8'}, (err, data) => {
if (err) {
return console.log(err.message);
}
let lines = data.split('\r\n');
for (let i = 0; i < lines.length; i++) {
db.run('INSERT INTO paragraphs (text) VALUES (?)', [lines[i]], (err) => {
if (err) {
return console.log(err.message);
}
});
}
});
});
app.get('/visualize_paragraphs', (req, res) => {
db.all('SELECT * FROM paragraphs', (err, rows) => {
if (err) {
throw err;
}
rows.forEach((row) => {
res.write('<h1>Visualize Paragraphs</h1>');
res.write(row.text + '<br>');
});
res.end();
});
});
app.get('/tag_paragraphs', (req, res) => {
let paragraph_id = req.query.paragraph_id;
let tag = req.query.tag;
if (paragraph_id && tag) {
db.run('UPDATE paragraphs SET tag = ? WHERE id = ?', [tag, paragraph_id], function (err) {
if (err) {
return console.log(err.message);
}
console.log(`Row(s) updated: ${this.changes}`);
});
res.send('<h1>Tag Paragraphs</h1>' +
'<p>Paragraph ' + paragraph_id + ' has been tagged as ' + tag + '</p>');
} else {
db.all('SELECT * FROM paragraphs', (err, rows) => {
if (err) {
throw err;
}
res.write('<h1>Tag Paragraphs</h1>' +
'<table>');
rows.forEach((row) => {
res.write('<tr><td>' + row.id + '</td><td>' + row.text + '</td></tr>');
});
res.write('</table>' +
'<form action="/tag_paragraphs" method="get">' +
'<label for="paragraph_id">Paragraph ID:</label>' +
'<input type="text" id="paragraph_id" name="paragraph_id"><br>' +
'<label for="tag">Tag:</label>' +
'<input type="text" id="tag" name="tag"><br>' +
'<input type="submit" value="Submit">' +
'</form>');
res.end();
});
}
});
app.listen(3000, () => {
console.log('Example app listening on port 3000!');
});

Related

req.file == undefined, always undefined

I want to upload the excel file on the MySQL database and then import it back,
I have uses the technologies :
express
multer
mysql2
read-excel-file
sequelize
But when I upload the excel, req.file is showing undefined. in the excel controller folder.
I have checked the multer twice but it seems to be right.
I don't know what is the problem ...
Your answer will help me.
Thanks
Server-side code:
const multer = require("multer");
const excelFilter = (req, file, cb) => {
if (
file.mimetype.includes("excel") ||
file.mimetype.includes("spreadsheetml")
) {
cb(null, true);
} else {
cb("Please upload only excel file.", false);
}
console.log("done");
};
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __basedir + "/uploads");
},
filename: (req, file, cb) => {
console.log(file.originalname);
cb(null, `${Date.now()}-bestfile-${file.originalname}`);
},
});
var uploadFile = multer({ storage: storage, fileFilter: excelFilter });
module.exports = uploadFile;
Excel controller
const db = require("../../models");
const Branch = db.bestdata;
const readXlsxFile = require("read-excel-file/node");
const upload = async (req, res) => {
try {
console.log(req);
if (req.file == undefined) {
return res.status(400).send({ msg: "No, Excel File Uploaded" });
}
let path = __basedir + "/uploads/" + req.file.filename;
readXlsxFile(path).then((rows) => {
// skip header
rows.shift();
let branchArray = [];
rows.forEach((row) => {
let branchtoArray = {
id: row[0],
branch_name: row[1],
mgr_id: row[2],
mgr_start_date: row[3],
};
branchArray.push(branchtoArray);
});
Branch.bulkCreate(branchArray)
.then(() => {
res.status(200).send({
message: "Uploaded the file successfully: " + req.file.originalname,
});
})
.catch((error) => {
res.status(500).send({
message: "Fail to import data into database!",
error: error.message,
});
});
});
} catch (error) {
console.log(error);
res.status(500).send({
message: "Could not upload the file: " + req.file.originalname,
});
}
};
const GetImport = (req, res) => {
Branch.findAll()
.then((data) => {
res.send(data);
})
.catch((err) => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving tutorials.",
});
});
};
module.exports = {
upload,
GetImport,
};
Router:
const express = require("express");
const router = express.Router();
const excelController = require("../controller/BestData/excel.controller.js");
const uploadFile = require("../middlewares/upload.js");
let routes = (app) => {
router.post("/upload", uploadFile.single("file"), excelController.upload);
router.get("/import", excelController.GetImport);
app.use("/excel", router);
};
module.exports = routes;
Snapshot of postman test
enter image description here
Excel File uploading
enter image description here
The answer is simple: Destination and path should be the same.:

uploading files from react to node js with multer

I want to upload files from the form data in react which is being posted by axios like this.
const addNewProduct = () => {
const newProduct = {
name: name,
cost: cost,
size: size,
color: color,
material: material,
discount: discount,
description: description,
category: category
};
const nulls = Object.values(newProduct).filter(p => p === null);
if(nulls.length === 0 && images.imageFiles) {
let productFormData = new FormData();
productFormData.append('productInfo', JSON.stringify(newProduct));
productFormData.append('productImages', images.imageFiles);
const addUrl = "http://localhost:8080/cpnl/addproduct";
axios({
method: "POST",
url: addUrl,
data: productFormData,
headers: { "Content-Type": "multipart/form-data" }
})
.then((response) => {
console.log(response.data.msg);
})
.catch((response) => {
console.error(response);
});
}else {
Notiflix.Notify.Warning("Check your inputs!");
console.log(nulls);
console.log("product: \n" + JSON.stringify(newProduct));
}
};
then I want to upload images with multer to images folder. this is my code:
const storage = multer.diskStorage({
destination: "./public/images",
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).array("productImages", 5);
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png/;
// 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!');
}
}
//receive form data from front-end and add new product to database
router.post('/addproduct', async (req, res) => {
upload(req, res, (err) => {
if(err) {
res.status(400).json({
msg: err
});
} else {
if(req.files == undefined) {
res.status(400).json({
msg: "Error: No file selected! please contact the developer."
});
} else {
data = req.body.productInfo;
res.status(200).json({
msg: "Files uploaded!"
});
console.log( "images: " + req.files);
console.log("data" + data);
}
}
});
});
first problem: I'm getting image files inside req.body.productImages and not inside req.files
second problem: when I send the request node js throws me this error:
TypeError: upload is not a function
why everything is messed up!?
Edit: I restarted the server and now I'm getting data but the files are not being uploaded. no error is shown.
UPDATE: second problem fixed
First Problem : You have used .array("productImages", 5); in your upload function. use .array("files", 5); to get the file in req.files.
Second Problem : I guess there is some typo error in your code upload(req, res, (err)... there is one extra bracket it should be only upload(req,res,err )...

express body-parser and multer value receiving issue?

I am giving post request /product/create with some value and an image.
if I console every value before
upload(req, res, (err) => {})
it is showing properly with out image info.
if I receive the value after upload(req, res, (err) => {})
No value is showing.
Full post request code:
app.post('/product/create', (req, res) => {
let filename;
upload(req, res, (err) => {
if(err){
res.render('index', {
msg: err
});
} else {
if(req.file == undefined){
res.render('index', {
msg: 'Error: No File Selected!'
});
} else {
res.render('index', {
msg: 'File Uploaded!',
filename = req.file.filename;
});
}
}
});
const product = {
title : req.body.title,
desc : req.body.desc,
image : filename,
}
});
configuring Multer:
const storage = multer.diskStorage({
destination: './public/uploads/',
filename: function(req, file, cb){
cb(null,file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).single('myImage');
function checkFileType(file, cb){
const filetypes = /jpeg|jpg|png|gif/;
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!');
}
}
Multer does not support 'req.file.filename' outside upload function. As filename, originalname, fieldname etc is inbuild API of multer. It is limited to upload function only.
Now, if you are trying to upload product values inside database then you have to create an insert function inside multer upload function only.

renaming uploaded file nodejs and multer

problem with file name in Multer
i am using express.js and multer to upload images to server. i act like this:
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "../client/member/upload");
},
filename: function (req, file, callback) {
console.log('1', 1);
callback(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
}
});
var upload = multer({ storage : storage}).single('userPhoto');
but the problem is that never file name changes.
my uploader handler:
function memberUpload(request, response) {
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, "../client/member/upload");
},
filename: function (req, file, callback) {
console.log('1', 1);
callback(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
}
});
var upload = multer({ storage : storage}).single('userPhoto');
var folderName = path.join(__dirname, '../', 'client/member/upload');
if (!fs.existsSync(folderName)) {
fs.mkdir(folderName, function (err) {
if (err) {
return response.status(500).send(err);
}
else {
upload(request, response, function (err) {
if (err) {
return response.status(400)
.send('No files were uploaded.');
}
var sentFile = request.files.file,
fileName = (request.files.file && request.files.file.name) ? request.files.file.name : 'test';
sentFile.mv(path.join(__dirname, '../', 'client/member/upload/', fileName), function (err) {
mime.lookup(path.join(__dirname, '../', 'client/member/upload/', fileName)); // => 'text/plain'
if (err) {
return response.status(500)
.send(err);
}
response.send({'location': '../member/upload/' + fileName});
});
});
}
});
}
else {
upload(request, response, function (err) {
if (err) {
return response.status(400)
.send('No files were uploaded.');
}
var sentFile = request.files.file,
fileName = (request.files.file && request.files.file.name) ? request.files.file.name : 'test';
sentFile.mv(path.join(__dirname, '../', 'client/member/upload/', fileName), function (err) {
mime.lookup(path.join(__dirname, '../', 'client/member/upload/', fileName)); // => 'text/plain'
if (err) {
return response.status(500)
.send(err);
}
response.send({'location': '../member/upload/' + fileName});
});
});
}
}
the file save into correct directory with name "blobid0.jpeg", "blobid1.png" and so on ...
what is my fault?
Here is my code for uploading any file(pdf, txt, png) to server.Hope this will help you.
exports.saveMedia = ((req, res) => {
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, (config.const.path.base + config.const.path.productReviewMedia));
},
filename: (req, file, callback) => {
callback(null, Date.now() + '-' + file.originalname);
}
});
const upload = multer({storage: storage}).any('file');
upload(req, res, (err) => {
if (err) {
return res.status(400).send({
message: helper.getErrorMessage(err)
});
}
let results = req.files.map((file) => {
return {
mediaName: file.filename,
origMediaName: file.originalname,
mediaSource: 'http://' + req.headers.host + config.const.path.productReviewMedia + file.filename
}
});
res.status(200).json(results);
});
});

How can I dynamically create userdefined folder for file upload using multer in nodejs?

i want to upload the file into a folder which should be get from form data submit by user. which is req.body.coursename
/*conditions for directory check*/
var isvalidate = function (data) {
var data = data;
var dir = '../uploads'+'/'+data;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
return dir;
} else {
return dir;
}
};
/*multer*/
var date = moment().format('YYYY-MM-DD');
var storage = multer.diskStorage ({
destination: function (req, file, callback) {
console.log("filename upload",file.originalname);
callback(null, isvalidate(req.body.coursename));
},
filename: function (req, file, callback) {
//console.log("filename upload",file.originalname);
callback(null, date+ '-' +file.originalname );
}
});
var data = multer({ storage : storage }).any();
/*file upload*/
router.post('/create',function(req, res) {
console.log(req.body);
data(req, res, function(err) {
console.log(req.body);
//isvalidate (req.body.coursename);
if (err) {
res.json({error_code:1,err_desc:err});
return;
}
});
});
How can I create a folder with the name req.body.coursename for file upload?
You can't but you can move the file to other locations after the file is uploaded. You could make your storage object a module and change the directory dynamically via init
var multer = require('multer'); // middleware for handling multipart/form-data,
// Constructor
module.exports = function (name) {
try {
// Configuring appropriate storage
var storage = multer.diskStorage({
// Absolute path
destination: function (req, file, callback) {
callback(null, './uploads/'+name);
},
// Match the field name in the request body
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
return storage;
} catch (ex) {
console.log("Error :\n"+ex);
}
}
OR Use busboy
var Busboy = require('busboy');
var fs = require('fs');
app.post('.....',fucntion(req, res, next){
var busboy = new Busboy({ headers: req.headers });
busboy.on('field', function(fieldname, val) {
req.body[fieldname] = val;
});
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
fstream = fs.createWriteStream("path/desiredImageName");
file.pipe(fstream);
fstream.on('close', function() {
file.resume();
});
})
return req.pipe(busboy);
})
OR you can use changedest
app.post('/api/:type', multer({
dest: './uploads/',
changeDest: function(dest, req, res) {
var newDestination = dest + req.params.type;
var stat = null;
try {
stat = fs.statSync(newDestination);
} catch (err) {
fs.mkdirSync(newDestination);
}
if (stat && !stat.isDirectory()) {
throw new Error('Directory cannot be created because an inode of a different type exists at "' + dest + '"');
}
return newDestination
}
}), function(req, res) {
//set your response
});

Resources