Formidable package treat some fields as Files - node.js

I'm using to parse form/data with the formidable package, it works great but some inputs are treated as files not as fields.
Example : I send the data from the front-end with the http package in flutter like this.
var request = http.MultipartRequest('POST', postUri)
..fields['username'] = _username!
..fields['password'] = _password!
..fields['address'] = _address!
..files.add(await http.MultipartFile.fromPath(
'coverPic',
_coverImage!.path,
contentType: MediaType('image', coverPicType),
));
All fields parsed successfully instead of the address, treated as file, I don't know why ! The text inside the address was :
it's near, don't be late
The function inside Node js:
function formDataParser() {
return (req, res, next) => {
const form = formidable({});
form.parse(req, (err, fields, files) => {
console.log(fields);
console.log(files);
if (err)
return next(err);
if (!fields || !Object.keys(fields).length)
return next(err);
if (!files || !Object.keys(files).length)
return next(err);
for (var file in files) {
const image = files[file];
if (!image.originalFilename || !image.size || !image.mimetype)
return next(new Error('File specification not found');
const imageName = image.originalFilename;
const imageExt = imageName.slice(
((imageName.lastIndexOf('.') - 1) >>> 0) + 2
);
if (image.size > 10000000) {
const error = new Error('File is too large! ' + imageName);
error.originalError = 'Throwing Custom Error';
error.statusCode = 403;
return next(error);
}
if (image.mimetype !== 'image/jpeg' && image.mimetype !== 'image/png' && image.mimetype !== 'image/jpg') {
const error = new Error('File type is not allowed! ' + imageName);
error.originalError = 'Throwing Custom Error';
error.statusCode = 403;
return next(error);
}
if (imageExt !== 'jpg' && imageExt !== 'jpeg' && imageExt !== 'png') {
const error = new Error('File extension is not allowed! ' + imageName);
error.originalError = 'Throwing Custom Error';
error.statusCode = 403;
return next(error);
}
}
if (!req.body)
req.body = {};
for (field in fields) {
req.body[field] = fields[field];
}
for (file in files) {
req.body[file] = files[file];
}
return next();
});
}
}

Related

How to consume a RESTful API in Node.js

I'm new to Node.js and I'm creating a simple pagination page. The REST API works fine, but consuming it has left me in limbo.
Here is the REST API (other parts have been taken out for brevity)
const data = req.query.pageNo;
const pageNo =
(typeof data === 'undefined' || data < 1) ? 1 : parseInt(req.query.pageNo);
let query = {};
const total = 10;
query.skip = (total * pageNo) - total;
query.limit = total;
try {
const totalCount = await Users.countDocuments();
const pageTotal = Math.ceil(totalCount / total);
const users = await Users.find({}, {}, query);
return res.status(200).json(users);
} catch (error) {
console.log('Error ', error);
return res.status(400).send(error)
};
};
When I return the json with just the 'users' object, like so return res.status(200).json(users); the page renders correctly, but when I pass in other objects like what I have in the code, it fails. This is how I'm consuming the API:
const renderHomepage = (req, res, responseBody) => {
let message = null;
if (!(responseBody instanceof Array)) {
message = 'API lookup error';
responseBody = [];
} else {
if (!responseBody.length) {
message = 'No users found nearby';
}
}
res.render('users-list', {
title: 'Home Page',
users: responseBody,
message: message
});
}
const homelist = (req, res) => {
const path = '/api/users';
const requestOptions = {
url: `${apiOptions.server}${path}`,
method: 'GET',
json: true,
};
request(
requestOptions,
(err, {statusCode}, body) => {
if (err) {
console.log('Ther was an error ', err);
} else if (statusCode === 200 && body.length) {
renderHomepage(req, res, body);
} else if (statusCode !== 200 && !body.length) {
console.log('error ',statusCode);
}
}
);
}
I've searched extensively on both here and other resources but none of the solutions quite answers my question. I hope someone could be of help

Node.js writing data to file throws an error

Got this error when I run my program
TypeError: Callback is not a function
// Update data from a new file
lib.update = function(dir,file,callback){
//Open the file for writing
fs.open(lib.baseDir+dir+'/'+'.json','r+',function(err,fileDescriptor){
if(!err && fileDescriptor){
var stringData= JSON.stringify(data);
//Truncate the file before writing
fs.truncate(fileDescriptor,function(err){
if(!err){
//Write to the file and close it
fs.writeFile(fileDescriptor,stringData,function(err){
if(!err){
fs.close(fileDescriptor,function(err){
if(!err){
callback(false);
}else {
callback('Error closing existing file!')
}
})
}else {
callback('Error writing to existing file')
}
});
}else {
callback('Error Truncating file')
}
});
}else {
callback('Could not open file for updating! May not exist yet')
}
});
}
I propose you to refactor your code to be a little more clear about what you are doing. Something like this, it will help you find where errors come. Using promises better than use a lot of callbacks.
Just my contribution.
lib.update = function(dir, file, data) {
const updateP = new CustomPromise();
openFile()
.then(truncateFile)
.then(writeFile.bind(this, JSON.stringify(data)))
.then(closeFile)
.then(updateP.resolve) // at this point all the functions was successful
.catch((errorType) =>
errorType !== ERROR_TYPE.ERROR_CLOSING_FILE // something fail try to close the file
? closeFile().finally(() => updateP.reject(errorType))
: updateP.reject(errorType),
);
return updateP.promise;
};
// Constants
const ERROR_TYPE = Object.freeze({
ERROR_OPEN_FILE: 'error-open-file',
ERROR_TRUNCATING_FILE: 'error-truncating-file',
ERROR_WRITING_FILE: 'error-writing-file',
ERROR_CLOSING_FILE: 'error-closing-file',
});
// Private functions
function CustomPromise() {
this.promise = new Promise(function(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
});
}
function openFile() {
const openP = new CustomPromise();
fs.open(lib.baseDir + dir + '/' + '.json', 'r+', function(err, fileDescriptor) {
(err || !fileDescriptor) && openP.reject(ERROR_TYPE.ERROR_OPEN_FILE);
openP.resolve(fileDescriptor);
});
return openP.promise;
}
function truncateFile(fileDescriptor) {
const truncateP = new CustomPromise();
fs.truncate(fileDescriptor, function(err) {
err && truncateP.reject(ERROR_TYPE.ERROR_TRUNCATING_FILE);
truncateP.resolve(fileDescriptor);
});
return truncateP.promise;
}
function writeFile(data, fileDescriptor) {
const writeFileP = new CustomPromise();
fs.writeFile(fileDescriptor, data, function(err) {
err && writeFileP.reject(ERROR_TYPE.ERROR_WRITING_FILE);
writeFileP.resolve(fileDescriptor);
});
return writeFileP.promise;
}
function closeFile(fileDescriptor) {
const closeP = new CustomPromise();
fs.close(fileDescriptor, function(err) {
err && closeP.reject(ERROR_TYPE.ERROR_CLOSING_FILE);
closeP.resolve();
});
return closeP.promise;
}

Multer - Stop File Uploading If Form Validation Fails

i have mixed form with file upload and normal form fields, and while sending this form to Nodejs server i am validating form but problem is that i do not know how to stop uploading the file if (for example) one of the form field is empty.
so for example:
if(name.trim().length < 1){
//stop uploading of file
return res.status(409).send({
message: 'provide name'
})
}
how can i do that (Multer & ExpressJS)?
I was using following code in my case (node & express).
From routes.js file I am calling this insertRating method. like below
//routes.js
router.post('/common/insertrating',RatingService.insertRating);
//controller class
// storage & upload are configurations
var storage = multer.diskStorage({
destination: function (req, file, cb) {
var dateObj = new Date();
var month = dateObj.getUTCMonth() + 1; //months from 1-12
var year = dateObj.getUTCFullYear();
console.log("month and yeare are " + month + " year " + year);
var quarterMonth = "";
var quarterYear = "";
var dir_path = '../../uploads/' + year + '/' + quarterMonth;
mkdirp(dir_path, function (err) {
if (err) {
console.log("error is cominggg insidee");
}
else {
console.log("folder is createtd ")
}
cb(null, '../../uploads/' + year + '/' + quarterMonth)
})
console.log("incomingggg to destination");
},
filename: function (req, file, cb) {
console.log("incoming to filename")
cb(null, Date.now() + "_" + file.originalname);
},
});
var upload = multer({
storage: storage,
limits: {
fileSize: 1048576 * 5
},
fileFilter: function (req, file, callback) {
var ext = path.extname(file.originalname);
ext = ext.toLowerCase();
console.log("ext isss " + ext);
if (ext !== '.png' && ext !== '.jpg' && ext !== '.jpeg' && ext !== '.pdf' && ext !== '.txt'
&& ext !== '.doc' && ext !== '.docx' && ext !== '.xlsx' && ext !== '.xls'
) {
return callback(new Error('Only specific extensions are allowed'))
}
callback(null, true)
}
}).array('files', 5);
// calling below insertRating method from routes js file...
exports.insertRating = async function (req, res) {
let quarterData = req.query.quarterData;
quarterData = JSON.parse(quarterData);
if (quarterData != null) { // here you can check your custom condition like name.trim().length
req.files = []; // not required
upload(req, res, async function (err) { // calling upload
if (err) {
res.send("error is cominggg")
return;
} else {
res.send("file is uploaded");
}
//
});
}
else {
res.send("filed must not be empty");
}
}
You can simply throw error:
in express::
app.get("/upload-image", multterUpload.single("image"), (req, res, next)=>{
try{
if(name.trim().length < 1) {
throw new Error("name length is not valid");
//or
return res.status(409).json({msg: "failed"});
}
// you all operation ....
res.status(200).json({msg: "success"});
}cathc(e=>{
next(e)
});
})
this is something you can do or you can return something else instead of throwing an error.

Cannot read property 'metadata' of null Nodejs

This is my error:
TypeError: Cannot read property 'metadata' of null
at gfs.files.findOne (M:\FinalProject\Commerce\routes\index.js:187:13)
at result (M:\FinalProject\Commerce\node_modules\mongodb\lib\utils.js:414:17)
This is my code :
router.get('/:filename', (req,res) => {
const img = req.params.filename; // Filename
gfs.files.findOne({filename: img}, (req,file) =>{
if(file.metadata.brand=="Mango"){
const brand = "Mango";
displayOne(brand);
}
else if(file.metadata.brand=="Cocotail")
{
const brand = "Cocotail";
displayOne(brand);
}
else if(file.metadata.brand==null)
{
console.log("Null");
}
function displayOne(brand)
{
gfs.files.find({'metadata.brand': brand }).toArray((err,files)=>{
if(!file || file.length ===0)
{
return res.status(404).json({
err: 'No files exist'
});
}
if(file.contentType === 'image/jpeg' || file.contentType === 'image/png')
{
file.isImage = true;
}
else
{
res.status(404).json({
err: 'Not an image'
});
file.isImage = false;
}
res.render('singleproduct',{
file:file,
relatedProduct:files, // Related Products
isSearch:0
});
});
}
});
});
Please give me any ideas about this error. i couldn't find out what is the major reason for this error. I searched on google but there are no appropriate solutions for that.____________________________________________________________________________________________________________________________________________________________________________________________________________________________________________
Thank you
Did you console what you get just above
(file.metadata.brand=="Mango")
in file? seems you don't get any data from
gfs.files.findOne({filename: img}
try this:
if(file && file.metadata.brand=="Mango"){
const brand = "Mango";
displayOne(brand);
}
else if(file && file.metadata.brand=="Cocotail")
{
const brand = "Cocotail";
displayOne(brand);
}
else if(file && file.metadata.brand==null)
{
console.log("Null");
}
else{
console.log("didinot find value")
}

HTTPS Request Inside app.post Doesn't work

I got problem where
https.get(urlDosen,res => {......});
not working as you can see in here:
function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
// ignore non-text-message event
return Promise.resolve(null);
}
const b = String(event.message.text);
if(b.substring(0,5)=='dosen'){
const namaDosen = b.substring(6);
const urlDosen = url+namaDosen;
https.get(urlDosen,res => {
console.log(res.headers['content-type']);
The code goes like this:
app.post('/callback', line.middleware(config), (req, res) => {
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result))
.catch((err) => {
console.error(err);
res.status(500).end();
});
});
// event handler
function handleEvent(event) {
if (event.type !== 'message' || event.message.type !== 'text') {
// ignore non-text-message event
return Promise.resolve(null);
}
const b = String(event.message.text);
if(b.substring(0,5)=='dosen'){
const namaDosen = b.substring(6);
const urlDosen = url+namaDosen;
https.get(urlDosen,res => {
console.log(res.headers['content-type']);
if(res.headers['content-type']=='application/json; charset=UTF-8'){
res.setEncoding('utf8');
let body = '';
res.on('data', data=>{
body += data;
});
res.on('end', ()=>{
body = JSON.parse(body);
if(body['hasil']=='sukses'){
const echo = {type:'text',text: 'Nama Dosen: ' + body['nama'] + ' Status: ' + body['status']};
return client.replyMessage(event.replyToken, echo);}
else{
const echo ={type:'text',text:body['status']};
return client.replyMessage(event.replyToken, echo);
}
}
);
} else{
const hasil={type:'text',text:'Mohon mengulang kembali'};
return client.replyMessage(event.replyToken, hasil);
// message.channel.send("Mohon mengulang kembali");
}
});
} else{
// create a echoing text message
const echo = { type: 'text', text: 'salahnya dimana?' };
// use reply API
return client.replyMessage(event.replyToken, echo);
}
}
I'm using node.js. Thanks

Resources