Node.js async consistency - javascript

I have the following code :
server.use(function(req, res, next) {
users_db.set(req.user, function(err) { // async call to mongodb
if (err) {
console.error(err);
}
});
}
return next();
});
server.get('/', function(req, res) {
req.user.active = true; // this is a new field in user object
res.send(req.user);
}
});
So, As you see, when users_db.set() is called, req.user doesn't have the active=true field. It is being inserted only in the server.get() function.
Is it possible that user.active = true is registered in the db nevertheless because of the asynchronous nature of the call ?

As far as I know (it is like that in Express at least) .get method accepts many middleware functions. So I guess that the following will work:
server.get(
'/',
function(req, res, next) {
req.user.active = true; // this is a new field in user object
res.send(req.user);
next();
},
function(req, res, next) {
users_db.set(req.user, function(err) { // async call to mongodb
if (err) {
console.error(err);
}
});
}
return next();
}
);
Doing the things like that you are sure that req.user.active is populated always before to reach the moment with users_db.set.

Related

Limit acces to users Node.js

I want to limit access to the /secrets route only to users
app.get("/secrets", function(req, res){
Post.find({}, function(err, posts){
res.render("secrets", {
posts: posts
});
});
});
I know it should be something like this:
app.get("/secrets", function(req, res){
if (req.isAuthenticated()){
res.render("secrets");
} else {
res.redirect("/login");
}
});
But I don't know how to proceed since I already have a callback function.
You can use middleware it goes something like this.
app.get("/secrets", secretsPermissionCheck, function(req, res){
// do your request processing
}
});
you can write below code in your middleware folder.
module.exports = function secretsPermissionCheck(req, res, next){
if(!isAuthenticated()) {
res.redirect("/login")
}else {
next();
}
}
The second code you gave is the wrapper, because first you check whether the user is authenticated. If so, then you operate normally and send a POST request to find posts, while if not, then you redirect to login.
app.get("/secrets", function(req, res){
if (req.isAuthenticated()){
//start
Post.find({}, function(err, posts){
res.render("secrets", {
posts: posts
});
});
//end
} else {
res.redirect("/login");
}
});
app.get('/secrets', checkAuthentication, function (req, res) {
Post.find({}, function (err, posts) {
res.render("secrets", {
posts: posts
});
});
});
function checkAuthentication(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/login");
}
}

the correct way using middleware in express

hey I want to make sure if I use the correct way for middleware in my simple express app, I am trying to find the email unique for register
here is my example
const isUnique = (req, res, next) => {
User.findOne({
where:{
email: req.body.email
}
})
.then(getUser => {
if(getUser){
next("/userAlreadyExist") // router
// or can i render to to html? i am using ejs
} else {
next()
}
})
.catch(next())
}
app.post('/register', isUnique ,(req, res) => {
res.send(`thank you for register`)
}
I want to make sure the email already exists or no, so I want to pass it on middleware first, and get a page for isUnique, if the email already in use, I want to redirect it to next router called '/emailExist', and if it success i want to redirect it to router /success
can anyone help me if that code wrong or no? just want to make sure :D
You have a lot of options, here are a couple.
You can redirect users to specific pages based on whether or not the email exists. Within your /emailAlreadyExists and /registerSuccess routes you can render whatever templates you want or return some data.
const isUnique = (req, res, next) => {
User.findOne({
where:{
email: req.body.email
}
})
.then(getUser => {
if (getUser) {
res.redirect('/emailAlreadyExists');
} else {
res.redirect('/registerSuccess'); // or just call next()
}
})
.catch(next("DB error"));
}
Pass along the results of the db query and let your final middleware handle it:
const isUnique = (req, res, next) => {
User.findOne({
where:{
email: req.body.email
}
})
.then(getUser => {
req.user = getUser;
next();
})
.catch(next());
}
app.post('/register', isUnique ,(req, res) => {
if (req.user) {
res.send('User already exists');
} else {
res.send(`thank you for register`);
}
}
You can also create an error handling middleware:
const isUnique = (req, res, next) => {
User.findOne({
where:{
email: req.body.email
}
})
.then(getUser => {
if(getUser){
next("Error: user already exists"); // or some other error message/object
} else {
next(); // continue to next middleware
}
})
.catch(next("DB error")); // handle errors throw from DB read
}
app.post('/register', isUnique ,(req, res) => {
res.send(`thank you for register`)
}
/*
If you call "next" with an argument, Express will skip
straight to this error handler route with the argument
passed as the "err" parameter
*/
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send(`An error occurred: ${err}`);
})

How to turn an export.signup and export.signin into a module.exports?

I'm developing a module which I'm using for passport authentication with ExpressJS, and I came up with this solution to gather all the passports methods I'm using:
// passport-controller-js
exports.signup = (passport) => (req, res, next) => {
// Authenticate methods ================
passport.authenticate('local-signup', function(err, user, info) {
if (err) {
return next(err); // will generate a 500 error
}
// Saving user...
return res.send({ success : true, message : 'signup succeeded' });
})(req, res, next);
};
exports.signin = (passport) => (req, res, next) => {
passport.authenticate('local-login', function(err, user, token, info) {
if (err) {
return next(err); // will generate a 500 error
}
req.login(user, loginErr => {
if (loginErr) {
return next(loginErr);
}
return res.send({ success : true, message : 'signin succeeded' });
});
})(req, res, next);
};
But since this module will increase adding more strategies I'm thinking if there is a way to put all of them inside a module.exports like:
module.exports = (passport) => {
function signin(req, res, next) {
passport.authenticate('local-login', function(err, user, token, info) {
if (err) {
return next(err); // will generate a 500 error
}
req.login(user, loginErr => {
if (loginErr) {
return next(loginErr);
}
return res.send({ success : true, message : 'signin succeeded' });
});
})(req, res, next);
};
I know that dosn't work Im just wondering if there is a possible solution like that so when I need to require those methods on my router file for example I can do this:
// auth.js (passport is passed from index.js)
const passportController = require('../controllers/passport-controller')(passport);
// Process the signup form
router.post('/signup', passportController.signup);
router.post('/signin', passportController.signin);
Instead of:
// auth.js (passport is passed from index.js)
const passportController = require('../controllers/passport-controller');
// Process the signup form
router.post('/signup', passportController.signup(passport));
router.post('/signin', passportController.signin(passport));
As you can see is just matter of looking for the most legible way to code and keep it simpler as possible.
Any help would be appreaciated, thank you very much.
Sounds like you want to make a module that exports a single function which returns an object. The syntax for that is
module.exports = passport => ({
signup(req, res, next) {
…
},
signin(req, res, next) {
…
}
});

Use an array of middlewares at express.js

I'm trying to use an array of middlewares. Well, more like a combination of function names and arrays.
Instead of having:
router.post('/editPassword', validate, changePassword, sendConfirmation);
I would like to have something like:
router.post('/editPassword', validate, [changePassword, sendConfirmation] );
That would look like:
router.post('/editPassword', validate, doAction );
Where doAction would be an array like this:
var doAction = [
//equivalent of changePassword
function(req, res, next){
//whatever
next();
},
//equivalent to the previous sendConfirmation
function(req, res, next){
//whatever
}
]
But it seems it is failing and going back to the validate step after the next() within the first function in doAction.
I'm looking for a way to simplify the middleware chaining including some middleware steps under the same name.
Latest version of Express can handle this:
function logOriginalUrl (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}
function logMethod (req, res, next) {
console.log('Request Type:', req.method)
next()
}
var logStuff = [logOriginalUrl, logMethod]
app.get('/user/:id', logStuff, function (req, res, next) {
res.send('User Info')
})
You can review more from this link
I assume the reason you wanted it to look that way is not only for it to appear presentable, but also to be able to reuse the other middleware. In that case, you can create a middleware which runs all other middlewares to do the check for you, and only calls the next function if all validations succeed.
var express = require('express');
var app = express();
function middleware1(req, res, next) {
if(req.query.num >= 1) {
next();
} else {
res.json({message: "failed validation 1"});
}
}
function middleware2(req, res, next) {
if(req.query.num >= 2) {
next();
} else {
res.json({message: "failed validation 2"});
}
}
function middleware3(req, res, next) {
if(req.query.num >= 3) {
next();
} else {
res.json({message: "failed validation 3"});
}
}
function combination(req, res, next) {
middleware1(req, res, function () {
middleware2(req, res, function () {
middleware3(req, res, function () {
next();
})
})
})
}
app.get('/', combination, function (req, res) {
res.send('Passed All Validation!');
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
You can test this app by running it then viewing http://localhost:3000/?num=3, changing the value 3 to a lower number, or removing the num parameter.
I'm not sure if this is the proper way to do it, but this is how I've handled my other projects. Let me know what you think.
note: see comments for use case. #robertklep may have a better solution depending on how you want to use middlewares
Just search a little more ^^ : Less ugly and more understandable than previous answer
https://github.com/blakeembrey/compose-middleware
Be careful that you're not doing (the equivalent of) this in your validate middleware:
function middleware(req, res, next) {
if (someCondition) {
console.log('some condition is true');
next();
}
console.log('some condition is false');
res.status(400).end();
}
The intention here is that after calling next the rest of the code isn't executed, but it will. There's nothing really special about next, so when you call it, after it returns the middleware code continues to run (causing both "some condition is true" and "some condition is false" to be logged).
That's why you often see this:
if (someCondition) {
console.log('some condition is true');
return next();
// Or, alternatively:
// next();
// return;
}
The return causes the middleware function to return after calling next, so the rest of the code in the function won't be executed.
This functionality is already built into express as an array or middleware:
let combined = express.Router()
.use(
[
middleware1,
middleware2,
middleware3,
],
);
let combined = express.Router()
.use(
middleware1,
middleware2,
middleware3,
);
Full Example
"use strict";
let Http = require("http");
let Express = require("express");
let server = Express();
let app = Express.Router();
let combined = Express.Router();
combined.use(
function (req, res, next) {
console.log("huzzah!");
next();
},
function (req, res, next) {
res.json({ success: true });
}
);
function middleware0(req, res, next) {
console.log('ground zero');
next();
}
app.get("/combined", middleware0, combined);
server.use("/", app);
Http.createServer(server).listen(3000);

Remove a field of my json in a specific case

I have an ExpressJS controller that list all my users
userCtrl.get :
get(req, res, next) {
var func = function(err, data) {
if (err) return next(err);
return res.json(data);
};
if (req.params[this.idName])
this._getById(req.params[this.idName], func);
else
this._getAll(func);
}
_getById(id, fn) {
this.ObjectClass.findById(id, fn);
}
_getAll(fn) {
this.ObjectClass.findAll(fn);
}
I'd like to call it from another road, in such a way that res.json() will filter a field of this json
Something like :
router.get ('/services/:serviceKey/authBridge/users', function(req, res, next) {
function anonJs(x) {
x.forEach(s => s.credential = null);
res.json(x);
}
res.json = anonJs;
userCtrl.get(req, res, next);
});
The problem is, with this last piece of code I end up with a recursion as I call res.json that is now defined as anonJS
You must store the reference to the old function before replacing it.
router.get ('/services/:serviceKey/authBridge/users', function(req, res, next) {
var json = res.json;
res.json = function(x) {
x.forEach(s => s.credential = null);
json(x);
}
userCtrl.get(req, res, next);
});

Categories