Express validator ".isEmpty()" not working - node.js

When I try to run my application I get an error saying that text boxes that are not empty are empty.
app.js:
https://pastebin.com/5pbVG7kq
index.hbs:
https://pastebin.com/neVV4X78

EDIT:
With express-validator, you need to use the "notEmpty()" function instead of validator's module "isEmpty()", which is not referenced in the readme.md. I tried it out with an empty string and without sending the parametr and it works fine in both cases.
OLD REPLY:
I'm facing the same issue with express-validator. I submitted the issue to the github respository so we have to wait for them to address the problem.
As a workaround in the meantime, you can use the isEmpty() function of the validator package directly.
var validator = require('validator');
validator.isEmpty(string) //returns true or false
Also note that validator only accepts a string value and it doesn't coerce the variable passed to it as opposed to express-validator, so you will need to handle the case when the parameter obtained via req.body.param is not sent.
Here is the link to the reported issue: https://github.com/ctavan/express-validator/issues/336
Hope this helps.

2019 express-validator
6.2.0
Here is what I use for now and it works perfect
app.js
const express = require('express');
const {createPost} = require('../controllers/post');
// Import check only form express-validator
const {check} = require('express-validator');
const router = express.Router();
router.post('/post',[
// Title
check('title').not().isEmpty().withMessage('Title is required.'),
check('title').isLength({
min:4,
max:150
}).withMessage('Title must be between 4 to 150 characters.'),
check('body').not().isEmpty().withMessage('Body is required.'),
check('body').isLength({
min:4,
max:2000
}).withMessage('body must be between 4 to 2000 characters.')
],createPost)
** Folder '../controllers/post'**
post.js
// Import validation result only from expres-validator
const {validationResult } = require('express-validator');
// Post model file with custom implementation.
const Post = require('../models/post');
exports.createPost = (req, res) => {
// Grab your validation errors here before making any CREATE operation to your database.
const errors = validationResult(req);
if (!errors.isEmpty()) {
const firstError = errors.array().map(error => error.msg)[0];
return res.status(400).json({ error: firstError });
}
const post = new Post({
title: req.body.title,
body: req.body.body
});
// Now you can safely save your data after check passes.
post.save()
.then(result => {
res.status(200).json({
post: result
})
});
};

Related

mongoose query of node api is working in postman but not in cyclic and railway server

const express=require('express');
const router=express.Router();
const Pokaranreading=require('../model/pokaranschema');
const moment = require('moment');
router.get('/todaydata',async (req,res)=>{
try {
const startOfToday=moment().startOf('day').toDate();
const endOfToday=moment().endOf('day').toDate();
const Pokreading=await Pokaranreading.find({
**RDate:{
$gte:startOfToday,
$lte:endOfToday
}**
});
res.status(201).json(Pokreading);
} catch (error) {
res.status(404).json(error)
}
})
this code is working with postman but not working in cyclic or railway server.
RDate:{
$gte:startOfToday,
$lte:endOfToday
}
when i commented this piece of code than cyclic/railway is returning data. But when RDate is not commented then cyclic/railway is returning empty array.
Please help`
You can use .toISOString() for better result.
const startOfToday=moment().startOf('day').toISOString();
const endOfToday=moment().endOf('day').toISOString();
I would suggest use console.log()or debug to see the value of RDate in the database

Express Rest Api: question about routing?

I have a Rest API where a user can create a list and then put list items in it (for a quiz). My schema structure is this:
const verbListSchema = {
title: String,
verbs: [{verb: String}]
};
Here are the url endpoints I have so far:
/lists/ (gets back all the lists)
/lists/verbs (gets all the verbs from all the lists)
My question is - I want to get, post, patch and delete a specific list using its id, like /lists?list_id=123/verbs or /lists/123/verbs and then one step further to get individual verbs I want to do something like /lists/123/verbs/124 or /lists?list_id=123/verbs?verb_id=124 the last doesn't work because it counts the last endpoint as a query param.
In terms of best practice what's the best way to do this. I could do something like this (I use express.js)?
app.[request-type]("/lists") {...}
app.[request-type]("/lists/:list_id") {...}
app.[request-type]("/lists/:list_id/verbs") {...}
app.[request-type]("/lists/:list_id/verbs/:verb_id") {...}
and then if I want to retrieve all the lists, not just a specific one I can check if the list_id is "all" like, /lists/all/verbs?
And here is my code so far:
const express = require("express");
const verbRouter = require("./verbRoutes");
const router = express.Router();
const VerbList = require("../../verb-list-db");
const isOriginal = async (req,res,next) => {
const listExists = await VerbList.find({title: req.body.listTitle})
if (listExists.length > 0 ) return res.status(400).json({message: "list already exists"});
next();
};
router.route("/")
.get(async (req,res,next) => {
try {
const listId = req.query.list_id;
if (listId) return res.json(await VerbList.find({_id: listId}));
const lists = await VerbList.find({});
res.json(lists);
} catch(err) {next(err)}
})
.post(isOriginal, async (req,res,next) => {
const newList = new VerbList({ // creates a new list
title: req.body.listTitle
})
newList.save()
.then(() => {return res.send("list successfully added!")})
.catch(err => next(err));
})
.patch(isOriginal, async (req,res,next) => {
try {
const listId = req.query.list_id;
if (!listId) throw new Error("you must have a list_id to patch!")
res.json(await VerbList.updateOne({_id: req.query.list_id}, {title: req.body.listTitle}))
} catch(err) {next(err)}
})
.delete(async (req,res,next) => {
try {
const listId = req.query.list_id;
if (!listId) throw new Error("you must have a list_id to delete!");
res.json(await VerbList.deleteOne({_id: req.query.list_id}))
} catch(err) {next(err)}
})
Any suggestions would be appreciated :)
You can try to modularize your express code by separating your /lists routes from your main server.js (or index.js) file.
index.js
const express = require('express');
const app = express();
//Now lets route all the API requests that start with '/list' to a file called lists.js
app.use('/lists', require('/path/to/lists.js')
app.listen(3000, () => console.log(`\nServer started on port 3000`))
lists.js
const express = require('express');
const router = express.Router();
// now you know all the requests in this file would be for /list so lets implement a router for fetching all the lists
router.get('/', async(req, res) => {
*** add all your logic for /lists endpoints here**
res.status(200).json(lists_json_response); //send a response back to your client
})
//you can create as many endpoints as you want in this file for endpoints that start with '/lists'
router.[request-method]("/lists/:list_id") {...} // endpoint for requesting a specific list
router.[request-method]("/:list_id/verbs") {...} //endpoint for requesting all the verbs for a specific list
router.[request-method]("/lists/all/verbs") {...} // all the verbs in all the lists
module.exports = router;
Also you cant put query parameters in the middle of an endpoint. if it is going to be a variable that you need and its not in the end of the URL, you have to pass it as a param, e.g.:
instead of doing /lists?list_id=123/verbs?verb_id=124, you can do something like /lists/123/verbs/124 to look for the verb with id 124 in a list with id 123.
so to listen to a request to this endpoint, you can design another endpoint in your lists.js file like this:
router[request-method].('/:list_id/verb/:verb_id', async(req, res)=> {
var list_id = req.params.list_id
var verb_id = req.params.verb_id
***
now use the list_id and verb_id to query the requested data and send a response back to the client
***
})

NodeJS MongoDB Times Out Loading Route

I am having troubles after moving all of my Controllers Routes and Models into their own files. I seem to only get a timeout when loading anything from the database and none of my console.log()'s run anymore, The model works and it posts the testPost (in the controller) perfectly fine. I tried adding the testPost because console.log() or errors aren't showing in my console.
Controller
//jshint esversion: 6
const mongoose = require('mongoose');
const Post = require(`./../models/posts`);
//Initial Post to posts Model
const testPost = new Post ({
postTitle: `Default Post`,
postDate: Date.now(),
postBody: `If you're seeing this, It means your DB is connected and you're ready to go!`,
postAuthor: `Admin`
});
const defaultPost = [testPost];
//View Single Post
exports.showOne = function(req, res){
const requestedPostTitle = req.params.id;
Post.findOne({postTitle: requestedPostTitle}, function(err, foundPost){
if (!err && foundPost){
const title = foundPost.postTitle;
const date = foundPost.postDate;
const content = foundPost.postBody;
const author = foundPost.postAuthor;
res.render(`./post/post`, {
title: title,
date: date,
content:content,
author:author
});
}
});
};
Model
//jshint esversion: 6
const mongoose = require(`mongoose`);
const postSchema = new mongoose.Schema ({
{SCHEMA DATA}
}
});
module.exports = mongoose.model(`Post`, postSchema);
exports.databaseName = `postsDB`;
index.js Routes
app.get(`/posts`, postPages.showAll);
app.get(`/post/:id`, postPages.showOne);
app.get(`/post/compose`, postPages.compose);
app.post(`/post/compose`, postPages.create);
Firstly I moved my database startup into it's own file called db.js as per this great article that was referenced to me by another SO user:
https://theholmesoffice.com/mongoose-connection-best-practice/
After moving the configurations into db.js I logged the errors as per the article:
// If the connection throws an error
mongoose.connection.on('error',function (err) {
console.log('Mongoose default connection error: ' + err);
});
I had not realised that I wouldn't get error logs on database startup without this.
Make sure to send a request only after the connection to the DB was established.

Req.body is not iterable in node.js

I am building mock restful API to learn better. I am using MongoDB and node.js, and for testing I use postman.
I have a router that sends update request router.patch. In my DB, I have name (string), price (number) and imageProduct (string - I hold the path of the image).
I can update my name and price objects using raw-format on the postman, but I cannot update it with form-data. As I understand, in raw-form, I update the data using the array format. Is there a way to do it in form-data? The purpose of using form-data, I want to upload a new image because I can update the path of productImage, but I cannot upload a new image public folder. How can I handle it?
Example of updating data in raw form
[ {"propName": "name"}, {"value": "test"}]
router.patch
router.patch('/:productId', checkAuth, (req, res, next) => {
const id = req.params.productId;
const updateOps = {};
for (const ops of req.body) {
updateOps[ops.propName] = ops.value;
}
Product.updateMany({_id: id}, {$set: updateOps})
.exec()
.then(result => {
res.status(200).json({
message: 'Product Updated',
request: {
type: 'GET',
url: 'http://localhost:3000/products/' + id
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
err: err
});
});
});
Using for...of is a great idea, but you can't use it like you are to loop through an object's properties. Thankfully, Javascript has a few new functions that turn 'an object's properties' into an iterable.
Using Object.keys:
const input = {
firstName: 'Evert',
}
for (const key of Object.keys(input)) {
console.log(key, input[key]);
}
You can also use Object.entries to key both the keys and values:
const input = {
firstName: 'Evert',
}
for (const [key, value] of Object.entries(input)) {
console.log(key, value);
}
I know this answer might be too late to help you but it might help someone in 2020 and beyond.
First, comment out this block:
//const updateOps = {};
//for (const ops of req.body) {
//updateOps[ops.propName] = ops.value;
//}
and change this line:
Product.updateMany({_id: id}, {$set: updateOps})
to this:
Product.updateMany({_id: id}, {$set: req.body})
Everything else is fine. I was having similar issues, but this link helped me:
[What is the difference between ( for... in ) and ( for... of ) statements in JavaScript?
To handle multi-part form data, the bodyParser.urlencoded() or app.use(bodyParser.json());body parser will not work.
See the suggested modules here for parsing multipart bodies.
You would be required to use multer in that case
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer();
// for parsing application/json
app.use(bodyParser.json());
// for parsing application/xwww-
app.use(bodyParser.urlencoded({ extended: true }));
//form-urlencoded
// for parsing multipart/form-data
app.use(upload.array());
app.use(express.static('public'));

Use Express Router to match a route

I'm trying to consolidate a bunch of route usage throughout my Express API, and I'm hoping there's a way I can do something like this:
const app = express()
const get = {
fetchByHostname({
name
}) {
return `hey ${name}`
}
}
const map = {
'/public/hostname/:hostname': get.fetchByHostname
}
app.use((req, res, next) => {
const url = req.originalUrl
const args = { ...req.body, ...req.query }
const method = map[url] // this won't work
const result = method(args)
return res.json({
data: result
})
})
I'm trying to avoid passing round the req and res objects and just handle the response to the client in one place. Is there an Express/Node/.js module or way to match the URL, like my map object above?
I really don't understand what you are trying to achieve, but from what i can see, your fectchByHostname({name})should be fetchByHostname(name) and you might be able to return hey $name. You should be sure you are using ES6 because with you args. Else you have to define the as in es5 args = {body: req.body, query: req.query};. Hope it helps.

Resources