Uploading Images error (NodeJs/Formidable) - node.js

I was using formidable#2.0.1 to upload form that contents image, following a tutorial thou. I got the below.
How to debug this error?
Error: The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
Controller.js
const formidable = require("formidable");
const _ = require("lodash");
const fs = require("fs");
const Project = require("../models/projectModel");
exports.create = (req, res) => {
let form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
if (err) {
return res.status(400).json({
error: "Image could not be uploaded",
});
}
let project = new Project(fields);
if (files.image) {
project.image.data = fs.readFileSync(files.image.path);
project.image.contentType = files.image.type;
}
project.save((err, result) => {
if (err) {
return res.status(400).json({
error: errorHandler(error),
});
}
res.json(result);
});
});
};
projectModel.js
const mongoose = require("mongoose");
const { ObjectId } = mongoose.Schema;
const projectSchema = new mongoose.Schema(
{
title: {
type: String,
trim: true,
require: true,
},
category: {
type: ObjectId,
ref: "Category",
required: true,
},
image: {
data: Buffer,
contentType: String,
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Project", projectSchema);

In Controller.js I changed files.image.path to files.image.filepath and also changed files.image.type to files.image.mimetype
Controller.js
const formidable = require("formidable");
const _ = require("lodash");
const fs = require("fs");
const Project = require("../models/projectModel");
exports.create = (req, res) => {
let form = new formidable.IncomingForm();
form.keepExtensions = true;
form.parse(req, (err, fields, files) => {
if (err) {
return res.status(400).json({
error: "Image could not be uploaded",
});
}
let project = new Project(fields);
if (files.image) {
project.image.data = fs.readFileSync(files.image.filepath);
project.image.contentType = files.image.mimetype;
}
project.save((err, result) => {
if (err) {
return res.status(400).json({
error: errorHandler(error),
});
}
res.json(result);
});
});
};

use multer npm its works fine
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
console.log(req.file, req.body)
})

Related

node js : test rest API

i'm new learner in backend node js ... in my code below i created an API for questions and it contains get,post,delete and edit
i wanted to test it using the extension rest client in VS code but when i type Get http://localhost:3000/api in route.rest file to test it,it stucks on waiting
is there a way to know if my API works good and can somebody please help me if i have mistake below?
thanks in advance
//server.js
// #ts-nocheck
const express = require('express');
const morgan = require('morgan');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const jwt = require('jsonwebtoken');
const questionRoutes = require('./routes/subscribers');
const cors = require('cors');
const http = require('http');
// Has to be move but later
const multer = require("multer");
const Question = require('./models/subscriber');
// express app
const app = express();
// Explicitly accessing server
const server = http.createServer(app);
// corsfffffffff
app.use(cors());
dotenv.config();
const dbURI = process.env.MONGO_URL || "mongodb://localhost:27017/YourDB";
mongoose.connect(dbURI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(result => server.listen(process.env.PORT || 3000) )
.catch(err => console.log(err));
// register view engine
app.set('view engine', 'ejs');
app.use(express.json);
// middleware & static files
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.use(morgan('dev'));
app.use((req, res, next) => {
res.locals.path = req.path;
next();
});
// routes
// question routes
app.use('/questions' , questionRoutes );
// 404 page
app.use((req, res) => {
res.status(404).render('404', { title: '404' });
});
//questionRoute.js
const express = require('express');
const questionController = require('../controllers/questionCon');
const questionApiController = require('../controllers/questionApiController');
const router = express.Router();
// API Routing
router.get('/api/', questionApiController.get_questions);
router.post('/api/add', questionApiController.create_question);
router.get('/api/:id', questionApiController.get_question);
router.delete('/api/delete/:id', questionApiController.delete_question);
router.put('/api/update/:id', questionApiController.update_question);
// EJS Routing for GUI
router.get('/create', questionController.question_create_get);
router.get('/', questionController.question_index);
router.post('/', questionController.question_create_post);
router.get('/:id', questionController.question_details);
router.delete('/:id', questionController.question_delete);
module.exports = router;
//question.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const questionSchema = new Schema({
questionTitle: {
type: String,
required: true,
},
description: {
type: String,
},
price: {
type: Number,
},
});
const Question = mongoose.model('Question', questionSchema);
module.exports = Question;
//questionAPIcontroller
const Question = require('../models/subscriber');
const validators = require('../validators');
let questionApiController = {
// Get a single question
get_question : async (req , res) => {
const id = req.params.id;
try {
const question = await Question.findById(id,(err, question) => {
if (err) return res.status(400).json({response : err});
res.send("hello")
res.status(200).json({response : question})
console.log("hello")
})
} catch (err) {
res.status(400).json(err);
}
},
// Get all the questions
get_questions: async (req , res) => {
try {
const questions = await Question.find((err, questions) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : questions})
})
} catch (err) {
res.status(400).json(err);
}
},
// Create a question
create_question : async (req , res) => {
const {error} = validators.postQuestionValidation(req.body);
if(error) return res.status(400).json({ "response" : error.details[0].message})
try {
const question = await new Question(req.body);
question.save((err, question) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : " Question created Successfully"})
});
} catch (err) {
res.status(400).json(err);
}
},
// Delete question
delete_question : async (req , res) => {
const id = req.params.id;
var questionExist = false;
var userId ;
const question = await Question.findById(id).then(result => {
questionExist = true;
userId = result.owner;
}).catch(err => {
questionExist = false;
res.status(400).json({response : err });
});
if(questionExist){
try {
Question.findByIdAndRemove(id ,(err, question) => {
// As always, handle any potential errors:
if (err) return res.json({response : err});
// We'll create a simple object to send back with a message and the id of the document that was removed
// You can really do this however you want, though.
const response = {
message: "Question successfully deleted",
id: question._id
};
return res.status(200).json({response : response });
});
} catch (err) {
res.status(400).json(err);
}
}
else {
return res.status(400).send( { "response" : "A question with that id was not find."});
}
},
// Update question
update_question : async (req , res) => {
const id = req.params.id;
Question.findByIdAndUpdate(id,req.body,
function(err, result) {
if (err) {
res.status(400).json({response : err});
} else {
res.status(200).json({response : "Question Updated"});
console.log(result);
}
})
},
// Get question's questions
}
module.exports = questionApiController
//questionController
const Question = require('../models/subscriber');
const question_index = (req, res) => {
Question.find().sort({ createdAt: -1 })
.then(result => {
res.render('index', { questions: result, title: 'All questions' });
})
.catch(err => {
console.log(err);
});
}
const question_details = (req, res) => {
const id = req.params.id;
Question.findById(id)
.then(result => {
res.render('details', { question: result, title: 'Question Details' });
})
.catch(err => {
console.log(err);
res.render('404', { title: 'Question not found' });
});
}
const question_create_get = (req, res) => {
res.render('create', { title: 'Create a new question' });
}
const question_create_post = (req, res) => {
const question = new Question(req.body);
question.save()
.then(result => {
res.redirect('/questions');
})
.catch(err => {
console.log(err);
});
}
const question_delete = (req, res) => {
const id = req.params.id;
Question.findByIdAndDelete(id)
.then(result => {
res.json({ redirect: '/questions' });
})
.catch(err => {
console.log(err);
});
}
module.exports = {
question_index,
question_details,
question_create_get,
question_create_post,
question_delete
}
change code
app.use(express.json);
to
app.use(express.json());

API for making query searches not working

I'm trying to fetch all records from MongoDB starting with the Alphabet S but every time I try doing so, it returns nothing but []. I'm using the Params tab on Postman to do this.
The code that I have written is below as well as a snip from Postman to make the question more understandable. I'm pretty sure that the API I have written to perform this has something wrong with it.
The Model file
const mongoose = require('mongoose');
const entry = new mongoose.Schema({
name : {
type : String,
},
collegeName : {
type : String,
},
location : {
type : String,
}
});
const enter = mongoose.model("Student", entry);
module.exports = enter;
index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const mongo = require('mongodb');
const dataModel = require('./model/model');
const MongoClient = mongo.MongoClient;
const uri = "mongodb+srv://coolhack069:XzC6N7dOyUeQl8M9#cluster0.kz6v9.mongodb.net/assignment?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
app.use(express.json());
app.use(bodyParser.json());
const port = 3001;
app.get('/api/get', (req, res) => {
client.connect(err => {
if(err) {
throw err;
}
const collection = client.db('assignment').collection('data');
const fetchedData = {};
collection.find(fetchedData).toArray(function(err, result) {
res.send(result);
client.close();
});
})
});
app.get('/api/getStudentDetails', (req, res) => { //The API I have written to query through the Database
client.connect(err => {
if(err) {
throw err;
}
const collection = client.db('assignment').collection('data');
const fetchedData = new dataModel({
name : req.params.name
});
collection.find(fetchedData).toArray(function(err, result) {
res.send(result);
client.close();
})
})
});
app.post('/api/add', (req, res) => { //To add Data
const name = req.body.name;
const collegeName = req.body.collegeName;
const location = req.body.location;
client.connect(err => {
if(err) {
throw err;
}
const collection = client.db('assignment').collection('data');
const storeData = new dataModel({
name : name,
collegeName : collegeName,
location : location
});
console.log(storeData);
collection.insertOne(storeData, function(err, result) {
res.json({
result : "Success"
});
console.log(err);
client.close();
});
})
});
app.listen(port, () => {
console.log(`Application running at http://localhost:${port}`)
})
The Screenshot from Postman
Your find condition is not correct:
const fetchedData = new dataModel({ // ???
name : req.params.name
});
collection.find(fetchedData).toArray(function(err, result) {
res.send(result);
client.close();
})
??? - I guest your meaning is const fetchedData = { name: req.params.name}; - Find every document which have name is req.params.name (S - in your case). But there is no document has name is S in your collection, then it returns [].
If you want to find the documents with S as the first character of their name, you can use Regex syntax:
const query = {
name : new RegExp('^' + req.params.name, 'i'), // i - case insensitive, => /^S/i
};
collection.find(query).toArray(function(err, result) {
res.send(result);
client.close();
})

Add a counter for url shortener in nodejs mongodb

Hello i'm building an app to shorten urls using nodejs and mongodb
I want to add a counter to each url added to the data base and how many times it was shortened for example
For now it just shortens the url once and gives me the date of the last time i shortened the url
this is my db.config
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const Url = require('../models/url');
const db = "mongodb://localhost:27017/url"
mongoose.createConnection(db, err =>{
if(err){
console.error('Error! ' + err)
} else {
console.log('Connected to mongodb url')
}
});
module.exports = router;
This is the model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const URLSchema = new Schema({
urlCode: String,
longUrl: String,
shortUrl: String,
date: {
type: String,
default: Date.now
}
});
module.exports = mongoose.model('url', URLSchema, 'urls');
and this is the api
const express = require('express');
const router = express.Router();
const validUrl = require('valid-url');
const shortid = require('shortid');
const config = require('config');
const Url = require('../models/url');
router.post('/shorten', async (req, res) => {
const { longUrl } = req.body;
const baseUrl = config.get('baseUrl');
// Check base url
if (!validUrl.isUri(baseUrl)) {
return res.status(401).json('Invalid base url');
}
// Create url code
const urlCode = shortid.generate();
// Check long url
if (validUrl.isUri(longUrl)) {
try {
let url = await Url.findOne({ longUrl });
if (url) {
res.json(url);
} else {
const shortUrl = baseUrl + '/' + urlCode;
url = new Url({
longUrl,
shortUrl,
urlCode,
date: new Date()
});
await url.save();
res.json(url);
}
} catch (err) {
console.error(err);
res.status(500).json('Server error');
}
} else {
res.status(401).json('Invalid long url');
}
});
router.get('/', (req, res) => {
Url.find({},(err, docs) => {
if (!err) { res.send(docs); }
else { console.log('Error in Retriving url :' + JSON.stringify(err, undefined, 2)); }
});
});
module.exports = router;
Updated Model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const URLSchema = new Schema({
urlCode: String,
longUrl: String,
shortUrl: String,
date: {
type: String,
default: Date.now
},
count: {
type: Number,
default: 0
});
module.exports = mongoose.model('url', URLSchema, 'urls');
And, the updated API
const express = require('express');
const router = express.Router();
const validUrl = require('valid-url');
const shortid = require('shortid');
const config = require('config');
const Url = require('../models/url');
router.post('/shorten', async (req, res) => {
const { longUrl } = req.body;
const baseUrl = config.get('baseUrl');
// Check base url
if (!validUrl.isUri(baseUrl)) {
return res.status(401).json('Invalid base url');
}
// Create url code
const urlCode = shortid.generate();
// Check long url
if (validUrl.isUri(longUrl)) {
try {
let url = await Url.findOne({ longUrl });
if (url) {
await Url.updateOne({ longUrl }, { count: url.count + 1 }, { upsert: true })
res.json(url);
} else {
const shortUrl = baseUrl + '/' + urlCode;
url = new Url({
longUrl,
shortUrl,
urlCode,
date: new Date()
});
await url.save();
res.json(url);
}
} catch (err) {
console.error(err);
res.status(500).json('Server error');
}
} else {
res.status(401).json('Invalid long url');
}
});
router.get('/', (req, res) => {
Url.find({},(err, docs) => {
if (!err) { res.send(docs); }
else { console.log('Error in Retriving url :' + JSON.stringify(err, undefined, 2)); }
});
});
module.exports = router;

Data not saving to mongodb

I'm currently trying upload images to a database by using Mutler and GridFS - which is successful. But I'm also trying to create a caption via the same form, but saving the data into a different schema. My problem is that on the POST route, it's not saving the data to the Posts schema - but no errors are being returned - but as well as that, I'm not being redirected the index page.
model.js schema for caption data
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const PostSchema = new Schema({
caption: {
type: String,
},
fileID: {
type: mongoose.Schema.Types.ObjectId,
ref: 'fs' //created by multer gridfs storage
}
});
const Posts = mongoose.model('Posts', PostSchema);
module.exports = { Posts };
app.js
// Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
app.use(methodOverride("_method"));
app.set("view engine", "ejs");
// Mongo URI
const mongoURI = "mongodb://localhost:27017/grid-fs";
// Mongo connection
const connection = mongoose.createConnection(mongoURI, { useNewUrlParser: true });
// Mongoose Schema
const { Posts } = require('./models/model');
// Init gfs
let gfs;
connection.once("open", () => {
// Init stream
gfs = Grid(connection.db, mongoose.mongo);
gfs.collection("uploads");
})
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString("hex") + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: "uploads"
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
app.get("/", (req, res) => {
gfs.files.find().toArray((err, files) => {
// Check if files exist
if (!files || files.length === 0) {
res.render("index", {files: false})
} else {
files.map(file => {
if(file.contentType === "image/jpeg" || file.contentType === "image/png") {
file.isImage = true;
} else {
file.isImate = false;
}
});
res.render('index', {files: files})
}
});
})
app.post('/upload', upload.single('file'), (req, res) => {
console.log(req.file)
const post = new Posts({
caption: req.body.caption,
fileID: req.file.id
});
console.log(req.body.caption)
console.log(req.file.id)
console.log(post)
post.save().then( result => {
res.redirect('/');
}).catch(err => {
res.status(400).send("Unable to save data");
});
});
I refresh the page the image is pushed to the frontend, but when I check the database the caption content is missing - no schema is there:
try this db.getCollectionNames() and check if your collection is there or not if it doesnot exists
try this
Posts.create({
caption: req.body.caption,
fileID: req.file.id
}, (err, data) => {
if (err) res.status(400).send("Unable to save");
else {
res.redirect("/")
}
})

How to validate multipart/form-data in Express-validator using Nodejs

A snippet of my code where i show my defined router,checking body param and checking for validation error.
My defined Post request:
router.post("/addEmployee",upload.any(), function(req, res, next) {
/*I used multer because body data from multipart/form-data*/
var input = JSON.parse(req.body.data);
Server validation: // validation not work because req.checkBody only get bodyData now i am using multipart/form-data (req.body.data)
req.checkBody('EMPID', "**EMPID must be Integer**").notEmpty().isNumeric();
req.checkBody('PAYROLLID', "**PAYROLLID must be Integer**").notEmpty().isNumeric();
.....
....
Check validation error
var validationError = req.validationErrors(); //check error
// if (validationError) { //suppose get error -- throw that error
res.json(validationError[0].msg);
} else { //validation success
......strong text
Use express validator middleware after the multer that's why express validator work naturally
This example work for me , try this
import require dependencies
var fs = require('fs');
var path = require('path');
var multer = require('multer');
var mkdirp = require('mkdirp');
configure multer
var obj = {};
var diskStorage = multer.diskStorage({
destination:function(req,file,cb){
var dest = path.join(__dirname,'/uploads');
mkdirp(dest,function(err){
if(err) cb(err,dest);
else cb(null,dest);
});
},
filename:function(req,file,cb){
var ext = path.extname(file.originalname);
var file_name = Date.now()+ext;
obj.file_name = file_name;
cb(null,file_name);
}
});
var upload = multer({storage:diskStorage});
prepare validation middleware
var validator = function(req,res,next){
req.checkBody('name').notEmpty().withMessage('Name field is required');
req.checkBody('email')
.notEmpty()
.withMessage('Email field is required')
.isEmail()
.withMessage('Enter a valid email address')
.isEmailExists()
.withMessage('Email address already exists');
req.checkBody('password').notEmpty().withMessage('Password field is required');
req.checkBody('retype_password').notEmpty().withMessage('Retyp password field is required');
req.checkBody('password').isEqual(req.body.retype_password).withMessage('Password and confirm password did not match.');
req.checkBody('address').notEmpty().withMessage('Address field is required');
req.asyncValidationErrors().then(function() {
next();
}).catch(function(errors) {
req.flash('errors',errors);
res.status(500).redirect('back');
});
}
save requested data into db
router.post('/store',upload.single('avatar'),validator,async function(req,res,next){
var newUser = User({
name:req.body.name,
email:req.body.email,
password:req.body.password,
avatar:obj.file_name,
address:req.body.address,
created_at:new Date()
});
try{
await newUser.save();
req.flash('success_message','New user has been successfully created');
return res.redirect('back');
}catch(err){
throw new Error(err);
}
});
Guys I find one solution
router.post("/addEmployee",upload.any(), function(req, res, next) {
/*I used multer because body data from multipart/form-data*/
var input = JSON.parse(req.body.data);
req.body = input;// solution this line
});
This works for me on the route part of desired endpoint
var express = require("express");
var router = express.Router();
const grant = require("../controllers/grant");
const { body, check } = require("express-validator");
const {
authenticate,
checkIfAdmin,
checkIfSuper,
checkIfApplicant,
} = require("../middlewares/authentication");
const { validateGrant } = require("../middlewares/validator");
const { uploadHandler } = require("../middlewares/call");
const {
multerUpload,
cloudinaryConfig,
paystack,
} = require("../config/config");
uploadHandler = (req, res, next) => {
req.upload(req, res, (err) => {
if (err) {
res.status(400)
.json({ message: `Bad request upload handler, ${err.message}`, success: false })
.end();
} else {
// special workaround for files validating with express-validator
req.body.files = req.files;
next();
// console.log("req.files", req.upload, "here", req.files, "body", req.body.files);
}
});
};
router.post(
"/create",
authenticate,
checkIfSuper,
function (req, res, next) {
req.upload = multerUpload.fields([
{ name: "main", maxCount: 1 },
{ name: "banner", maxCount: 1 },
]);
next();
},
uploadHandler,
[
check("name").not().isEmpty().withMessage("Grant Name is required"),
check("description")
.isString()
.withMessage("Grant Description is required"),
check("sdgGoals")
.not()
.isEmpty()
.withMessage("Grant Sdg Goals are required"),
check("deadline")
.not()
.isEmpty()
.withMessage("Grant Application Deadline is required"),
check("available")
.isBoolean()
.withMessage("Grant Availability is required"),
check("about").isString().withMessage("Grant About is required"),
check("by").isString().withMessage("Grant Creator is required"),
],
cloudinaryConfig,
grant.create
);
grant.create is
const { error } = require("../middlewares/response");
const { grants } = require("../models/grant");
const { validationResult } = require("express-validator");
const Datauri = require("datauri/parser");
const path = require("path");
const { uploader } = require("../config/config");
exports.create = async function (req, res, next) {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
success: false,
message: errors.array()[0].msg,
});
}
if (!req.files) {
return res.status(400).json({
success: false,
message: "No files were uploaded",
});
}
const dUri = new Datauri();
const dataUri = (file) =>
dUri.format(path.extname(file.originalname).toString(), file.buffer);
const {
title,
description,
sdgGoals,
applicationDeadline,
applicationLimit,
available,
} = req.body;
let promises = [];
let imgs = [];
// console.log("req.files", req.files, "here", req.body.files);
for (const key in req.files) {
if (Object.hasOwnProperty.call(req.files, key)) {
const f = req.files[key][0];
console.log(f, "before uri")
//console.log(dataUri(f)); -> //fileName: '.png', mimetype: 'image/png', and content
const file = dataUri(f).content;
try {
const resp = await uploader.upload(file);
// console.log("resp url and image", resp.url, image);
imgs.push({ name: key, url: resp.url });
} catch (err) {
return next(err);
}
}
}
console.log("imgs", imgs);
const grant = new Grant({
...req.body,
createdBy: req.user._id,
images: imgs,
});
const result = await grant.save();
return res.status(201).json({
message: "Grant created successfully",
data: {
grant: result,
},
});
} catch (err) {
next(err);
}
};
exports.create = function (req, res) {
req.assert('name', 'Name cannot be blank').notEmpty();
req.assert('email', 'Email is not valid').isEmail();
req.assert('password', 'Password cannot be blank').notEmpty();
req.assert('password', 'Password must be at least 8 chars long').isLength({ min: 8 });
const errors = req.validationErrors();
if (errors) {
return res.status(200).send(errors);
}
req.body.password = bcrypt.hashSync(req.body.password, 10);
var model = new Admin(req.body);
model.save(function (err, admin) {
if (err) {
res.status(500).send({ error: err });
return;
} else {
res.status(200).send(admin);
}
});
};

Resources