Protect controller functions with session values in a extra function - node.js

I have some session values that describes if a user is an admin or not. currently I do something like this:
exports.DeleteUser = function (req, res) {
if(req.session == undefined || req.session.Lv < 80){
res.render("Login");
return;
}
//Code
res.render(...);
}
So if someone want to access the page and no session values or if the session value "Lv" is less than 80 the user would get to the login.
I have ~20 controller functions and writing that code block 20 times seems a bit to much.
What would be a efficient way to write this in a function? The only way I see would be a function with a return value true or false but then I still need an if with the "return" in it with would makes this only 1 row shorter.. Or can this be done Controller wide?

You can solve this issue following way :
// Session or valid user checker
// middleware function
// file : sessionChecker.js
const sessionChecker = (req, res, next) => {
if(req.session == undefined || req.session.Lv < 80){
res.redirect('/login');
}
else {
next();
}
};
module.exports = sessionChecker;
Router
const sessionChecker = require('./sessionChecker.js');
const blogController = require('./blogController.js');
const userController = require('./userController.js');
// use sessionChecker middleware for check session
router.get('/blogs', sessionChecker, blogController.index);
router.get('/users', sessionChecker, userController.index);
Controller
// File : blogController.js
const BlogController = module.exports = {
/**
* Index method
* #param req
* #param res
* #return {Promise<void>}
*/
index: async (req, res) => {
let data = {
pageTitle: "Blog Lists",
blogs : await blogRepo.get(req, res),
};
res.render('home', data);
}
}

Related

:ERR_EMPTY_RESPONSE after two minutes timeout -axios-post - nodejs

I'm trying do make an upload of a file in a nodejs / react application.
The upload of the file work well, but I have some issues when I want to have the response of my await.post() request. When I upload the file I have made a spinner to show that the file is uploading, and I want this spinner to stop when the upload is finish and then display a message to inform the user that the loading is finish.
I explain the problems, because it's a little bit complicated.
When i work in local :
After two minutes (I timed it to understand), the console of my browser display the error message net::ERR_EMPTY_RESPONSE.
But in server side everything continue and the request ended without a hitch. But in front side my spinner never stop turning even when the request is over and when my post request is sending the res message to my client side.
I thought this was about the timeout of my server, so I've done a lot of test, by putting setTimeout in my server :
var server = app.listen(PORT, () =>
console.log(`Server started on port ${PORT}`)
);
server.timeout = 3840000;
And also in my route request :
router.post('/', async (req, res) => {
req.setTimeout(3600000);
And even i try to change the timeout of my axios.post function in the client side :
const res = await axios.post('/api/students', newFile, {
timeout: 3600000,
});
But nothing handle my problem.
And what is strange is that when the application is hosted, the problem is different!
In fact there are no error message but after 1 minutes the spinner stop with no reason.
I have made a lot of research but nothing answer my problem, it's been a few day now that i'm on it and i don't understand why. I thought maybe it's a proxy problem or a browser timeout, but I don't know...
If you have even a small lead, it could help me a lot! Thank you for your help !
UPDATE :
The code of my /api/student route
const express = require('express');
const router = express.Router();
const fileUpload = require('express-fileupload');
const Student = require('../../models/Student');
const CSVToJSON = require('csvtojson');
const utf8 = require('utf8');
var accents = require('remove-accents');
const NodeGeocoder = require('node-geocoder');
const sleep = require('util').promisify(setTimeout);
let msg = 'Etudiants ajoutés à la base de données';
//The column that we want to keep in the database
const goodColumn = [
'Civilite',
'Nom_patronymique',
'Prenom',
'Date_naissance',
'No_etudiant',
'Libelle_nationalite',
'Telephone_portable',
'Mailum',
'Adresse_fixe_postal',
'Adresse_fixe_ville',
'Libelle_etape',
];
// Set up the environnement for geocoding the adress
const options = {
provider: 'openstreetmap',
};
const geoCoder = NodeGeocoder(options);
//FUNCTION TO VERIFY IF A STRING HAS A NUMBER IN IT
function hasNumber(myString) {
return /\d/.test(myString);
}
router.post('/', (req, res, next) => {
// This should be BEFORE `fileUpload`
req.setTimeout(0);
next();
});
router.use(fileUpload());
//#route POST api/students
//#desc Fill the database with the json information
//#access Public
router.post('/', async (req, res, next) => {
//FORMER FILES ROUTES
//take the information
const buf = Buffer.from(req.files.file.data).toString();
//CONVERSION CSV STRING TO JSON
CSVToJSON()
.fromString(buf)
.then((source) => {
for (let i = 0; i < source.length; i++) {
for (let j = 0; j < Object.keys(source[i]).length; j++) {
const columnName = Object.keys(source[i]);
columnName.forEach((element) => {
if (!goodColumn.includes(element)) {
delete source[i][element];
}
if (element == 'Libelle_etape') {
const str = source[i]['Libelle_etape'];
const result = accents.remove(utf8.decode(str));
source[i]['Libelle_etape'] = result;
}
});
}
}
data = JSON.stringify(source);
datajson = JSON.parse(data);
//USE THE FUNCTION TO PUT THE DATA IN THE DB
insertIntoDataBase(datajson);
});
// CLEAR TABLE BEFORE ADD NEW STUDENTS FROM FILE
Student.deleteMany({}, function (err) {});
//ROUTES STUDENTS - FUNCTION TO PUT THE JSON DATA IN THE DATABASE
async function insertIntoDataBase(jsonString) {
for (let i = 0; i < jsonString.length; i++) {
console.log(`boucle ${i}`);
try {
//READ DATA FROM DE CSV FILE (already convert into json data) AND PUT IT INTO VARIABLES
let {
Civilite,
Nom_patronymique,
Prenom,
Date_naissance,
No_etudiant,
Libelle_nationalite,
Telephone_portable,
Mailum,
Adresse_fixe_postal,
Adresse_fixe_ville,
Libelle_etape,
} = jsonString[i];
console.log(Nom_patronymique + ' ' + Prenom);
// VERIFICATION VILLE STRING FORMAT ( AVOIR NUMBER OR ..EME)
if (hasNumber(Adresse_fixe_ville)) {
Adresse_fixe_ville = Adresse_fixe_ville.replace(/[0-9]/g, '');
if (Adresse_fixe_ville.endsWith(' EME')) {
Adresse_fixe_ville = Adresse_fixe_ville.substring(
0,
Adresse_fixe_ville.length - 4
);
}
}
//VERIFICATION OF THE PHONE NUMBER - if empty attributes a default value
if (Telephone_portable !== undefined && Telephone_portable.length < 1) {
Telephone_portable = '0000000000';
}
// GEOCODING THE ADDRESS TO CONVERT INTO LATITUDE AND LONGITUDE
geoCoder
.geocode({
city: Adresse_fixe_ville,
zipcode: Adresse_fixe_postal,
})
.then(async (res) => {
//TEST
var Latitude;
var Longitude;
if (res[0] !== undefined) {
Latitude = res[0].latitude;
Longitude = res[0].longitude;
} else {
console.log(Adresse_fixe_ville);
Latitude = 0.0;
Longitude = 0.0;
}
//CREATE A STUDENT WITH THE INFO + LAT AND LONG
student = new Student({
Civilite,
Nom_patronymique,
Prenom,
Date_naissance,
No_etudiant,
Libelle_nationalite,
Telephone_portable,
Mailum,
Adresse_fixe_postal,
Adresse_fixe_ville,
Libelle_etape,
Latitude,
Longitude,
});
//VERIFICATION IF ALL THE ATTRIBUTE OF THE STUDENT ARE OK - IF NOT : undefined
if (
!(
student.Civilite === undefined ||
student.Nom_patronymique === undefined ||
student.Prenom === undefined ||
student.Date_naissance === undefined ||
student.No_etudiant === undefined ||
student.Libelle_nationalite === undefined ||
student.Telephone_portable === undefined ||
student.Mailum === undefined ||
student.Adresse_fixe_postal === undefined ||
student.Adresse_fixe_ville === undefined ||
student.Libelle_etape === undefined
)
) {
//SAVE THE STUDENT IN THE DATABASE
await student.save();
} else {
res.status(500);
msg =
'Le fichier csv téléchargé est au mauvais format de données';
}
})
.catch((err) => {
console.log(err);
});
} catch (err) {
console.log(err.message);
res.status(500);
msg =
'Erreur serveur, veuillez réessayer avec un fichier csv au bon format';
return;
}
//WAIT FOR GEOCODER - 1,2 second
await sleep(1200);
}
//COUNT A MANY STUDENT WE HAVE IN THE DATABASE
Student.find().exec(function (err, results) {
var count = results.length;
res.json({ msg: msg, count: count });
});
}
});
//#route GET api/students
//#desc Return all the students in the database (all information / attributes)
//#access Public
router.get('/', function (req, res, next) {
Student.find(function (err, students) {
if (err) {
res.send(err);
}
res.json(students);
});
});
module.exports = router;
In Node < 13.0.0 the default socket timeout is 2 minutes, so after two minutes the socket will be closed and you'll get ERR_EMPTY_RESPONSE on the client-side since the socket was closed without allowing you to respond to that request.
From Node 13.0.0 the default timeout was set to 0 (no timeout), and that's maybe the reason it works when you deployed the application, your server may be running Node >= 13.0.0.
If after using req.setTimeout with a value greater to 2 minutes, and you still have that issue, it may be caused because you're not ending the request correctly or you have used req.setTimeout in the wrong place.
It a huge file, it's a csv with 1300 ligne, it's take approximatly
30min to upload
From your comment, I can tell you that the req.setTimeout you have in your route is not doing what you want, because you have a middleware before that, probably multer from seeing at your code that is not setting the req.setTimeout to >30 min.
So the request is timing out before it reaches your route. You should do something like this:
app.post(
'/',
(req, res, next) => {
// Set request setTimeout BEFORE any other middlewares
req.setTimeout(ms('35m')); // using `ms` package
next();
},
upload.single('file'), // or whatever multer setup you have
(req, res, next) => {
// Your route
}
)
With this code, you have 35 minutes to upload & end your response, since it won't timeout at multer middleware after 2 minutes. Of course if you don't know how much time it will take, most likely the case, you can use req.setTimeout(0) or whatever value you consider appropiate.
Update
For your code, you'll have to do the following:
// or router.use((req, res, next) => ...)
router.post('/', (req, res, next) => {
// This should be BEFORE `fileUpload`
req.setTimeout(0);
next();
});
router.use(fileUpload());
//#route POST api/students
//#desc Fill the database with the json information
//#access Public
router.post('/', async (req, res, next) => {
// ...rest of your code
})

NodeJS RESTful API - How to handle 'undefined' request variables properly?

I am developing a RESTful API using NodeJS and Express.
I noticed that incoming requests sometimes lack of some expected variables, which cause the program to crash, saying it couldn't set the value of a variable, to an 'undefined' value - as no value arrived with the request.
Example:
The application is expecting variableY, but instead variableX is being sent:
formData: { variableX: 'valueX' }
The program is expecting to receive variableY, with the following code:
const checkVariables = Joi.validate({
variableY: req.body.variableY,
}, schema);
The application crashes with the following error:
TypeError: Cannot read property 'variableY' of undefined
I thought about a few ways to handle that, including declaration of variables upon application initiation and using them along, using try-catch.
Another way will be to use if-else, if-chaining, or case-switch, but as you understood of course I am looking for the cleanest way to achieve that.
Any ideas?
Thank you.
** EDIT **
Progressed and managed to achieve the result using the object only. Once trying to reach any of it's inner fields the error will be thrown anyway, example:
if(req.body.variableY == undefined){console.log('The expected variable is undefined');} //true
When the validation addresses a field inside the 'undefined' object:
if(req.body.variableY.dataId == undefined){console.log('The expected variable is undefined');} //crashes
The following error is being thrown again:
TypeError: Cannot read property 'variableX' of undefined
After doing some more digging around, found this Stackoverflow thread:
How to check if object property exists with a variable holding the property name?
Tried using hasOwnProperty, but the same kind of error is being thrown:
TypeError: Cannot read property 'hasOwnProperty' of undefined
Tried wrapping variable declaration using try-catch, still didn't work:
try{
var variableX = req.body.variableX
var variableXDataId = req.body.variableX.dataId
}
catch(e){
res.status(400).send('Wrong request error: Please check your request variables and try again');
}
As this is a really basic validation that should be addressed by most of the RESTful APIs (validating that you get the expected incoming variables inside the request, so the program won't crash by having errors it can't handle - what is the common solution for such problems (expected / unexpected request validation)?
Thank you.
You can take another approach, check req.body before you reach checkVariables:
let body = req.body;
// data - your req.body
// requiredKeys - is an array of strings , [ key1, key2 ... keyN] | string[]
const setKeys = ( data, requiredKeys )=>{
if( !typeof requiredKeys.length ){
requiredKeys = [];
}
if(requiredKeys.length) requiredKeys.forEach( k =>{
k = k.replace(/\+/g,'/');
let keysList = [];
if( /\/+/g.test(k)){
keysList = k.split('/');
}else{
keysList = [k];
}
let [firstKey, ...rest] = keysList;
if( typeof data[firstKey] === 'undefined' ){
data[firstKey] = {};
}
if( rest.length ){
data[firstKey] = setKeys(data[firstKey], [rest.join('/')] );
}
})
return data;
}
let checkedData= setKeys(body, ['variableT','variableP/noname/emptyObj','custom/object/does/not/exist/but/it/will/be/created/here']);
const checkVariables = Joi.validate(checkedData, schema);
UPDATE
Below you will find an working example on how things should work during a /(let's say /usersStatus/:id ) request:
const express = require('express')
const app = express()
const port = 3000
const setKeys = (data, requiredKeys) => {
if (!typeof requiredKeys.length) {
requiredKeys = [];
}
if (requiredKeys.length) requiredKeys.forEach(k => {
k = k.replace(/\+/g, '/');
let keysList = [];
if (/\/+/g.test(k)) {
keysList = k.split('/');
} else {
keysList = [k];
}
let [firstKey, ...rest] = keysList;
if (typeof data[firstKey] === 'undefined') {
data[firstKey] = {};
}
if (rest.length) {
data[firstKey] = setKeys(data[firstKey], [rest.join('/')]);
}
})
return data;
}
/**
* Mock some data
*/
const getUserData = (req, res, next) => {
if (typeof req.body === 'undefined') {
req.body = {};
}
req.body = {
variableY: {
someName: 23
},
variableZ: {
name: 3,
type: {
id: 5,
typeName: 'something',
tags: ['a', 'b', 'c']
}
}
};
console.log('Middleware 1 getUserData');
next();
}
/**
* 1. Setup our middleware for checking keys
* "requiredKeys" is an array of strings
*/
const middlewareSetKeys = (requiredKeys, wrappedMiddleware) => {
return (req, res, next) => {
console.log('Middleware 2 middlewareSetKeys');
if (typeof req.body === "undefined") {
console.log('Leaving Middleware 2 since we don\'t have req.body');
next();
}
/**
* Update "req.body" with keys that we want to have available
* in our next middleware
*/
req.body = setKeys(req.body, requiredKeys);
if (typeof wrappedMiddleware === 'function') {
return wrappedMiddleware.call(this, req, res, next);
} else {
next();
}
}
}
/**
* 2. Let's assume a "user status" situation
* 2.1. We need userInfo from database
* 2.2. Some info won't be retrieved, unless the user accesed some parts of the website to trigger some mechanisms that allows those fields to be exposed, therefore the lack of keys
* 2.3. But we know those keys/objects, and we still want to be present so our code won't crash.
*/
// lets call our getUserData
app.get(
'/', // this path is for some userInfo
getUserData, // this returns userInfo and appends it to `req.data`
middlewareSetKeys([
'userActivity/daily/jobs', // these won't exist in getUserData because the user is lazy and he didn't apply for any JOBS
'userStatus/active/two-weeks-ago', // these won't exist in getUserData because the user joined two days ago. BUT WE STILL NEED IT coz reazons.
]), // We set our desired-later-to-use keys
(req, res, next) => {
/**
* 3. Now our req.body will have our keys
* even if they didn't exist in the getUserData middleware
*/
console.log('Middleware 3 Your middleware');
console.log(req.body);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(req.body, null, 2))
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
you can use express validator https://www.npmjs.com/package/express-validator
to validate incoming request.Then add this to your controller where a,b,c ,d are parameters you want to valaidate
const nonEmptyFields = ['a', 'b', 'c', 'd'];
nonEmptyFields.forEach(field => req.assert(field, `${field} cannot be blank`).notEmpty());
const errors = req.validationErrors();
if (errors) {
return res.status(400).send(errors);
}
for validating a field inside a field you can try doing this
typeof(req.body && req.body.name !== undefined)
A solution will be to set a default empty object to replace undefined at a parent level:
// checking for body.variableX.variableZ with object destructuring ES6
const {body = {}} = request;
const {variableX = {}, variableY} = body;
const {variableZ} = variableX.variableZ;
// or prior ES6
var body = request.body || {};
var variableX = body.variableX || {};
var variableY = variableX.variableY;
// or in a statement
var variableY = request.body && request.body.variableX ? request.body.variableX.variableY : undefined;
Based on that you can create your own function like getValue(request, 'body.variableX.variableY') to return null if any parent or the end value is undefined:
// asumes the value in the path is either object or undefined
function getValue(rootObj, path = '') {
const parts = key.split('.');
let value = rootObj || {};
let part;
while ((part = parts.shift()) && value !== null) {
value = value[part] || null;
}
return value;
};

Express.js Designing Error Handling

I'm stuck on how to design error handling in an Express.js application.
What are the best design practices to handle errors in Express?
To my understanding, I can handle errors in 2 different ways:
First way would be to use an error middleware and, when an error is thrown in a route, propagate the error to that error middleware. This means that we have to insert the logic of the error handler in the middleware itself (note, the middleware here was purposely kept simple).
app.post('/someapi', (req, res, next) => {
if(req.params.id == undefined) {
let err = new Error('ID is not defined');
return next(err);
}
// do something otherwise
});
app.use((err, req, res, next)=>{
// some error logic
res.status(err.status || 500).send(err);
});
Another option is to deal with the errors on the spot, when the error happens. This means that the logic must be in the route itself
app.post('/someapi', (req, res, next) => {
if(req.params.id == undefined) {
let err = new Error('ID is not defined');
// possibly add some logic
return res.status(ErrorCode).send(err.message);
}
// do something otherwise
});
What is the best approach, and what are the best design practices for this?
Thank you
I think there are much more extensive cases but the main idea is using middleware design. Add your validation logic to this middleware.
yourRouter.post('/message', routerValidator.messageValidator, yourController.saveMessage.bind(yourController));
Below is my sample structure;
// controller
const BaseRoute = require('../infra/base/BaseRoute');
const log = require('./../../utils/log-helper').getLogger('route-web');
const { ErrorTypes } = require('../infra/middlewares/ErrorMiddleware');
const GameService = require('../../service/GameService');
const { SystemMessages } = require('../../statics/default_types');
module.exports = class WebController {
constructor() {
this._logger = log;
this._gameService = new GameService();
}
getGameInfo(req, res) {
var self = this;
try {
const info = self._gameService.getGameInfo(req.body.query);
return BaseRoute.success(res, { info });
} catch (err) {
self._logger.error('Something went wrong while getting game information', err);
return BaseRoute.internalError(res, SystemMessages.GENERIC_ERROR, req.getErrorCode(ErrorTypes.UNHANDLED, 1));
}
}
};
// router index
const express = require('express');
const ErrorMiddleware = require('../infra/middlewares/ErrorMiddleware').ErrorMiddlewarePath;
const baseValidator = require('../infra/validators/BaseRouterValidator');
const AndroidController = require('./AndroidController');
const IosController = require('./IosController');
const WebController = require('./WebController');
const AndroidRouter = express.Router();
const IosRouter = express.Router();
const WebRouter = express.Router();
const androidController = new AndroidController();
const iosController = new IosController();
const webController = new WebController();
AndroidRouter.post('/message', ErrorMiddleware(1), baseValidator.teamQueryValidator, androidController.getGameInfo.bind(androidController));
IosRouter.post('/message', ErrorMiddleware(1), baseValidator.teamQueryValidator, iosController.getGameInfo.bind(iosController));
WebRouter.post('/message', ErrorMiddleware(1), baseValidator.teamQueryValidator, webController.getGameInfo.bind(webController));
module.exports = {
AndroidRouter,
IosRouter,
WebRouter
};
// validator
const log = require('../../../utils/log-helper').getLogger('route-validator-base');
const BaseRoute = require('../base/BaseRoute');
const _ErrorTypes = require('../middlewares/ErrorMiddleware').ErrorTypes;
function teamQueryValidator(req, res, next) {
if (!req.body || !req.body.query) {
const params = req.body ? JSON.stringify(req.body) : 'Empty';
log.error('Invalid Parameters req body', params);
return BaseRoute.httpError(res, 'Bir takım adı giriniz..', 400, req.getErrorCode(_ErrorTypes.VALIDATION, 1));
}
return next();
}
module.exports = {
teamQueryValidator
};
// app.js that assigns to express
this._router = require('./src/route/api/index');
this._ErrorMiddleware = require('./src/route/infra/middlewares/ErrorMiddleware').ErrorMiddlewareRouter;
this.app.use('/api/android', this._ErrorMiddleware(1), this._router.AndroidRouter);
this.app.use('/api/ios', this._ErrorMiddleware(2), this._router.AndroidRouter);
this.app.use('/api/web', this._ErrorMiddleware(3), this._router.WebRouter);
What are the best design practices to handle errors in Express?
There is no best design, it's all subjective.
To my understanding, I can handle errors in 2 different ways:
Correct. You used error middleware for the first and then handled the error directly in the route handler.
To me, it makes sense to separate out the error handling logic from the business logic. It makes for cleaner code. So the former (error middleware) would be better IMO.
You would have a different error handler for different errors.

Not getting any response - Express Validator

I'm using the latest version of express-validator for validation.
I'm not getting any response, However Old method i.e checkBody is working fine while new method i.e check('keyName') is not working properly.
Below is my code.
package.json
"express-validator": "^5.0.3",
routes.js
var authValidator = require('./../validation/auth.validation');
var routes = require('express').Router();
routes.post('/login', [
authValidator.validateLogin,
authValidator.checkValidationResult ], function (req, res) {
console.log('3');
//res.send("Some other stuffs");
}
);
module.exports = routes;
auth.validation.js
module.exports.validateLogin = validateLogin;
module.exports.checkValidationResult = checkValidationResult;
const {check, validationResult} = require('express-validator/check');
const {matchedData, sanitize} = require('express-validator/filter');
var response = require('./../general/MyResponse');
var messages = require('./../general/messages');
function validateLogin(req, res, next) {
console.log('1');
return [
check('email').isLength({min: 1}).withMessage(messages.EMAIL_REQUIRED)
.isEmail().withMessage(messages.INVALID_EMAIL),
check('password').isLength({min: 1}).withMessage(messages.PASSWORD_REQUIRED),
]
}
function checkValidationResult(req, res, next) {
console.log('2');
var result = validationResult(req)
if (!result.isEmpty()) {
response.createResponse(
res, 400,
result.array()[0].msg,
{'error': result.array()[0].msg}, {}
)
} else {
next()
}
}
I've noticed that node js not able to go ahead from the function validateLogin in auth.validation.js.
Can anyone tell me what's wrong with above code.
Inside console, Only 1 is displaying.
I'm attaching screenShot for referance.
We need to use simple Array and don't need to create function.
Follow this link
Is it possible to do the validation in a separate file and not inline in the route? - GitHub for more details.
Code should be like this.
auth.validation.js
var response = require('./../general/MyResponse');
var messages = require('./../general/messages');
const {check, validationResult} = require('express-validator/check');
const {matchedData, sanitize} = require('express-validator/filter');
module.exports.validateLogin = [
check('email').isLength({min: 1}).withMessage(messages.EMAIL_REQUIRED).isEmail().withMessage(messages.INVALID_EMAIL),
check('password').isLength({ min: 1 }).withMessage(messages.PASSWORD_REQUIRED),
];
module.exports.checkValidationResult = checkValidationResult;
function checkValidationResult(req, res, next) {
console.log('2');
var result = validationResult(req)
if (!result.isEmpty()) {
response.createResponse(res, 400,
result.array()[0].msg,
{'error': result.array()[0].msg}, {}
)
} else {
next()
}
}
`
validateLogin and checkValidationResult are being applied as middlewares to your route. In middlewares you use next()method to call next middleware in the queue. Just like in your checkValidationResult.
In case of validateLogin, its not passing control to next middleware. But check method from express-validator v5 is itself a middleware method. Thus I guess it won't work correctly.
Please have a look at: https://github.com/ctavan/express-validator/issues/449
Try using following Code:
routes.js
var authValidator = require('./../validation/auth.validation');
var routes = require('express').Router();
var authValidations = authValidator.getAuthValidations();
routes.post('/login',
authValidations,
authValidator.checkValidationResult, function (req, res) {
console.log('3');
//res.send("Some other stuffs");
}
);
module.exports = routes;
auth.validations.js
module.exports.getAuthValidations = getAuthValidations;
module.exports.checkValidationResult = checkValidationResult;
const {check, validationResult} = require('express-validator/check');
const {matchedData, sanitize} = require('express-validator/filter');
var response = require('./../general/MyResponse');
var messages = require('./../general/messages');
function getAuthValidations(req, res, next) {
return [
check('email').isLength({min: 1}).withMessage(messages.EMAIL_REQUIRED)
.isEmail().withMessage(messages.INVALID_EMAIL),
check('password').isLength({min: 1}).withMessage(messages.PASSWORD_REQUIRED),
]
}
function checkValidationResult(req, res, next) {
console.log('2');
var result = validationResult(req)
if (!result.isEmpty()) {
response.createResponse(
res, 400,
result.array()[0].msg,
{'error': result.array()[0].msg}, {}
)
} else {
next()
}
}

How to access the GET parameters after "?" in Express?

I know how to get the params for queries like this:
app.get('/sample/:id', routes.sample);
In this case, I can use req.params.id to get the parameter (e.g. 2 in /sample/2).
However, for url like /sample/2?color=red, how can I access the variable color?
I tried req.params.color but it didn't work.
So, after checking out the express reference, I found that req.query.color would return me the value I'm looking for.
req.params refers to items with a ':' in the URL and req.query refers to items associated with the '?'
Example:
GET /something?color1=red&color2=blue
Then in express, the handler:
app.get('/something', (req, res) => {
req.query.color1 === 'red' // true
req.query.color2 === 'blue' // true
})
Use req.query, for getting he value in query string parameter in the route.
Refer req.query.
Say if in a route, http://localhost:3000/?name=satyam you want to get value for name parameter, then your 'Get' route handler will go like this :-
app.get('/', function(req, res){
console.log(req.query.name);
res.send('Response send to client::'+req.query.name);
});
Query string and parameters are different.
You need to use both in single routing url
Please check below example may be useful for you.
app.get('/sample/:id', function(req, res) {
var id = req.params.id; //or use req.param('id')
................
});
Get the link to pass your second segment is your id example: http://localhost:port/sample/123
If you facing problem please use Passing variables as query string using '?' operator
app.get('/sample', function(req, res) {
var id = req.query.id;
................
});
Get link your like this example: http://localhost:port/sample?id=123
Both in a single example
app.get('/sample/:id', function(req, res) {
var id = req.params.id; //or use req.param('id')
var id2 = req.query.id;
................
});
Get link example: http://localhost:port/sample/123?id=123
Update: req.param() is now deprecated, so going forward do not use this answer.
Your answer is the preferred way to do it, however I thought I'd point out that you can also access url, post, and route parameters all with req.param(parameterName, defaultValue).
In your case:
var color = req.param('color');
From the express guide:
lookup is performed in the following order:
req.params
req.body
req.query
Note the guide does state the following:
Direct access to req.body, req.params, and req.query should be
favoured for clarity - unless you truly accept input from each object.
However in practice I've actually found req.param() to be clear enough and makes certain types of refactoring easier.
#Zugwait's answer is correct. req.param() is deprecated. You should use req.params, req.query or req.body.
But just to make it clearer:
req.params will be populated with only the route values. That is, if you have a route like /users/:id, you can access the id either in req.params.id or req.params['id'].
req.query and req.body will be populated with all params, regardless of whether or not they are in the route. Of course, parameters in the query string will be available in req.query and parameters in a post body will be available in req.body.
So, answering your questions, as color is not in the route, you should be able to get it using req.query.color or req.query['color'].
The express manual says that you should use req.query to access the QueryString.
// Requesting /display/post?size=small
app.get('/display/post', function(req, res, next) {
var isSmall = req.query.size === 'small'; // > true
// ...
});
const express = require('express')
const bodyParser = require('body-parser')
const { usersNdJobs, userByJob, addUser , addUserToCompany } = require ('./db/db.js')
const app = express()
app.set('view engine', 'pug')
app.use(express.static('public'))
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.get('/', (req, res) => {
usersNdJobs()
.then((users) => {
res.render('users', { users })
})
.catch(console.error)
})
app.get('/api/company/users', (req, res) => {
const companyname = req.query.companyName
console.log(companyname)
userByJob(companyname)
.then((users) => {
res.render('job', { users })
}).catch(console.error)
})
app.post('/api/users/add', (req, res) => {
const userName = req.body.userName
const jobName = req.body.jobName
console.log("user name = "+userName+", job name : "+jobName)
addUser(userName, jobName)
.then((result) => {
res.status(200).json(result)
})
.catch((error) => {
res.status(404).json({ 'message': error.toString() })
})
})
app.post('/users/add', (request, response) => {
const { userName, job } = request.body
addTeam(userName, job)
.then((user) => {
response.status(200).json({
"userName": user.name,
"city": user.job
})
.catch((err) => {
request.status(400).json({"message": err})
})
})
app.post('/api/user/company/add', (req, res) => {
const userName = req.body.userName
const companyName = req.body.companyName
console.log(userName, companyName)
addUserToCompany(userName, companyName)
.then((result) => {
res.json(result)
})
.catch(console.error)
})
app.get('/api/company/user', (req, res) => {
const companyname = req.query.companyName
console.log(companyname)
userByJob(companyname)
.then((users) => {
res.render('jobs', { users })
})
})
app.listen(3000, () =>
console.log('Example app listening on port 3000!')
)
you can simply use req.query for get query parameter:
app.get('/', (req, res) => {
let color1 = req.query.color1
let color2 = req.query.color2
})
The url module provides utilities for URL resolution and parsing. URL parse without using Express:
const url = require('url');
const queryString = require('querystring');
let rawUrl = 'https://stackoverflow.com/?page=2&size=3';
let parsedUrl = url.parse(rawUrl);
let parse = queryString.parse(parsedUrl.query);
// parse = { page: '2', size: '3' }
Another way:
const url = require('url');
app.get('/', (req, res) => {
const queryObject = url.parse(req.url,true).query;
});
url.parse(req.url,true).query returns { color1: 'red', color2: 'green' }.
url.parse(req.url,true).host returns 'localhost:8080'.
url.parse(req.url,true).search returns '?color1=red&color2=green'.
Just use the app.get:
app.get('/some/page/here', (req, res) => {
console.log(req.query.color) // Your color value will be displayed
})
You can see it on expressjs.com documentation api:
http://expressjs.com/en/api.html
A nice technique i've started using with some of my apps on express is to create an object which merges the query, params, and body fields of express's request object.
//./express-data.js
const _ = require("lodash");
class ExpressData {
/*
* #param {Object} req - express request object
*/
constructor (req) {
//Merge all data passed by the client in the request
this.props = _.merge(req.body, req.params, req.query);
}
}
module.exports = ExpressData;
Then in your controller body, or anywhere else in scope of the express request chain, you can use something like below:
//./some-controller.js
const ExpressData = require("./express-data.js");
const router = require("express").Router();
router.get("/:some_id", (req, res) => {
let props = new ExpressData(req).props;
//Given the request "/592363122?foo=bar&hello=world"
//the below would log out
// {
// some_id: 592363122,
// foo: 'bar',
// hello: 'world'
// }
console.log(props);
return res.json(props);
});
This makes it nice and handy to just "delve" into all of the "custom data" a user may have sent up with their request.
Note
Why the 'props' field? Because that was a cut-down snippet, I use this technique in a number of my APIs, I also store authentication / authorisation data onto this object, example below.
/*
* #param {Object} req - Request response object
*/
class ExpressData {
/*
* #param {Object} req - express request object
*/
constructor (req) {
//Merge all data passed by the client in the request
this.props = _.merge(req.body, req.params, req.query);
//Store reference to the user
this.user = req.user || null;
//API connected devices (Mobile app..) will send x-client header with requests, web context is implied.
//This is used to determine how the user is connecting to the API
this.client = (req.headers) ? (req.headers["x-client"] || (req.client || "web")) : "web";
}
}

Resources