how to redirect from a view in keystone.js - async.js

What is the right way to redirect from within a keystone.js view?
I have this use case:
//req, res are the express request and response objects defined earlier
view.on('init', function(next){
if (req.params['should-be-else-where']='true'{
// do some logging stuff
// redirect to somewhere else
}
});
as I understand the next param in the view.on() function is a callback for the async.js framework, and does not relate to the (req,res,next) middleware.
Should I call res.redirect('/somewhere-else) and then call next(), then call next() with a non-null error parameter, or should redirection be performed somewhere completely different?
Additional info: I'd like to stop processing because there is no reason to do the performance heavy database processing that following later in the queue

If you don't need a View but only redirect if the condition was met, you could do it like this:
module.exports = function (req, res, next) {
if (req.params['should-be-else-where']) {
// do some logging stuff
res.redirect('/somewhere-else');
} else {
var view = new keystone.View(req, res);
// do something else then render the view
}
}

Related

How to create flash messages in Express/NodeJS?

This question has been asked a million times already, but I never really understood the answers and when I did, they did not suit my specific needs.
I currently have flash messages implemented using this:
app.use(function(req, res, next){
res.locals.sessionFlash = req.session.sessionFlash;
delete req.session.sessionFlash;
next();
});
And when I want to use the message in a route, I have to explicitly recall it like this:
res.render('...', {
sessionFlash: res.locals.sessionFlash
});
Is there a simpler way to do this (preferably one where I would not need to pull the messages from the session manually)?
This behavior is used by big frameworks such as sails.js
you can see code here: https://github.com/balderdashy/sails/blob/0506f0681590dc92986985bc39609c88b718a997/lib/router/res.js
you can achieve it in various ways, but these are the simplest.
1: overriding
you can override the function through "middlewares"
app.use( function( req, res, next ) {
// grab reference of render
var _render = res.render;
// override logic
res.render = function( view, options, fn ) {
// do some custom logic
_.extend( options, {session: true} );
// continue with original render
_render.call( this, view, options, fn );
}
next();
} );
I took this snippet from: https://stackoverflow.com/a/24051339/5384679
you can replicate without lodash etc.
2: wrapping render in a new function
make your own function to wrap the session flashMessage, you can use this to your advantage, i used some es6 syntax out of laziness, but could be replaced easily by es5 code.
res.sendView = function(path, options) {
this.render(path, {
sessionFlash: res.locals.sessionFlash,
...options
});
}
// now you can use res.sendView instead of res.render.

How to skip part of the middlewares that are on the stack in Express js

I am working on a backend of web application. And I have made a bunch of middlewares to be executed for each request that comes in -- [logging(before), authentication, Etag(Before), Nonce, httpRequest, Etag(after), logging(after)]. Now my problem is that, while processing each request, there are some special cases happen when the request should skip the rest of the middleware and just do logging. I can do it the dump way just make all the middleware to check if certain condition has happened and if true just call next(), and otherwise process the request using the middleware. But I am wondering if there is a clever way to do this?
Here is the snippet of the code I am currently using to configure the order of the middleware to be executed:
async.series(operations, function(err) {
if(err) {
console.log('Something blew up!!!!!!');
return next(err);
}
console.log('middleware get executed');
// no errors so pass control back to express
next();
});
Where the "operations" variable is the list of middlewares I need to execute in order. I need to use the async.series() since I need to make the order the middleware configurable. Is there a clever I can keep the order of middlewares configurable and fulfill my request as I said above?
EDIT:
An example where I need to skip the rest of the middleware is when authentication fails and write the statusCode to be "401 unauthorized", then for the stack of the middleware [logging(before), authentication, Etag(Before), Nonce, httpRequest, Etag(after), logging(after)], I will jump from authentication to logging(after). and then that would be the end of the request.
I had tried to understand your's concern
I am giving a snippet to execute middle ware function in row on the basis of need.
async.each(operations, function(operation, callback) {
if(operation) {
// if operation is required execute here
callback();
} else {
// otherwise skip just to call callback() here
callback();
}
}, function(err){
if( err ) {
console.log(err);
} else {
next();
}
});
all the operations in an array and to execute all one by one async provides .each.
Its not mandatory to call each operation. You just skip by call callback() in else condition. I want to say that in if clause you can put your mandatory execution condition.
Thanks

always run a middleware in expressjs

i want an expressjs middlware to be executed always.
That is even if there is an error in the next() or not.
is it possible?
example
app.get('/',[middle1,middle2],doIt)
the middle2 should always execute even if the middle1 executes next with error.
NOTE: the middle2 should always execute last and takes the values calculated by the previous middlewares. also there are lot of middlewares between middle1 and middle2.
If middle1 is known to not use any async operations from which it calls next(), then you can wrap it and put a try/catch around it so that if it throws, you can just call next() on its behalf.
If it does use async operations or you don't know if it will use async operations, then you will only catch its exceptions if it throws synchronously (before it goes async) and you will not be able to catch any exceptions that it throws asynchronously. About the best you could do for async behavior is to set some sort of timeout in your wrapper. If it hasn't called next() within some period of time (either because it threw an exception or just failed in some other weay), then you call next after the timeout period.
Wrapping a non-async middle1 could look like this:
function wrap(fn) {
return function(req, res, next) {
var nextCalled = false;
try {
fn(req, res, function() {
nextCalled = true;
next();
});
} finally {
if (!nextCalled) {
next();
}
}
}
}
app.get('/',[wrap(middle1),middle2],doIt);
The wrap() function inserts a stub as the middleware function. That stud inserts its own next() function so it can tell if the actual middleware function calls next() or not. It then wraps an exception handler around the middleware function so if it throws an exception synchronously, then it can recover. After the function returns, it checks to see if next() was called and, if not, it calls it.
As explained earlier this approach only works if the middleware function is synchronous.
Assuming you do not care about the order of execution, you can simply have function middle2 execute inside app.use.
app.use(middle2);
app.get('/pathx, middle1, middle3, doIt);
middle2 will always be executed on every request. However, middle2 will execute before any of the other middleware
If you require middle2 to execute last in sequence, then a simple modification using the async module should accomplish what you want
async = require('async');
function middleware(req, res, next){
var functionList = [middle1, middle3];
async.series(functionList, function(err, results){
if(err){
middle2(req, res, next);
next(err);
}
middle2(req, res, next);
next();
}
}
app.get('/pathX', middleware, doIt);

How does Express/Connect middleware work?

I am learning Node.js, and I have read some tutorials, like The Node Beginner Book for learning the core funcionality. But the more I read some examples, the more doubts I start collecting.
On the further example, obtained from a tutorial, we can see that for a CRUD 'read' request for key /documents/titles.json, we are returning a value:
app.get('/documents/titles.json', loadUser, function(req, res) {
Document.find({ user_id: req.currentUser.id },[], { sort: ['title', 'descending'] },
function(err, documents) {
res.send(documents.map(function(d) {
return { title: d.title, id: d._id };
}));
});
});
On this example, the function loaduser() is used for authentication purposes:
function loadUser(req, res, next) {
if (req.session.user_id) {
User.findById(req.session.user_id, function(err, user) {
if (user) {
req.currentUser = user;
next();
} else {
res.redirect('/sessions/new');
}
});
}
}
What I don't understand is:
I suppose that node.js, before start executing the app.get, it goes to loaduser function. loadUser() function has three parameters: req,res,next, but I don't see, at least, how you pass from app.get() the "req" parameter to loadUser(). From where does it come?
Inside loadUser() function, when you execute next(), it means that the function app.get()" can continue its procedure, but this req.currentUser = user, is the same req that is used on app.get() function?
Inside loadUser() function, when you execute res.redirect() code, automatically breaks the procedure on app.get() function, right? it looks like it doesn't return to Document.find().
The questions you've asked are about the Express framework internals specifically:
When you call app.get(route, loadUser, final) Express will make a stack (array) with the loadUser and final function functions and it will know that when you call next it should execute the following function in the stack with the same req and res params.
When you call next it will just pass to the next function in the middleware stack.
Since you call res.redirect and you don't call return, it won't pass to the next function in the stack (the one with Document.find).
Resources:
http://howtonode.org/getting-started-with-express
I think in order to be comfortable with this you need get familiar with idea of middleware and how it's used in connect framework.
I've found few articles where this subject explained well enough. Take a look there:
http://howtonode.org/connect-it
and here http://stephensugden.com/middleware_guide/
the main idea is you have a set of layers and each time when new request arrives it goes through each level and on each level you can decide what to do with that. You can stop at some level, do something and return response or you can pass it to the next layer

Remove route mappings in NodeJS Express

I have a route mapped as:
app.get('/health/*', function(req, res){
res.send('1');
});
How can I remove / remap this route to an empty handler at runtime?
This removes app.use middlewares and/or app.VERB (get/post) routes. Tested on express#4.9.5
var routes = app._router.stack;
routes.forEach(removeMiddlewares);
function removeMiddlewares(route, i, routes) {
switch (route.handle.name) {
case 'yourMiddlewareFunctionName':
case 'yourRouteFunctionName':
routes.splice(i, 1);
}
if (route.route)
route.route.stack.forEach(removeMiddlewares);
}
Note that it requires that the middleware/route functions have names:
app.use(function yourMiddlewareFunctionName(req, res, next) {
... ^ named function
});
It won't work if the function is anonymous:
app.get('/path', function(req, res, next) {
... ^ anonymous function, won't work
});
Express (at least as of 3.0.5) keeps all of its routes in app.routes. From the documentation:
The app.routes object houses all of the routes defined mapped by the associated HTTP verb. This object may be used for introspection capabilities, for example Express uses this internally not only for routing but to provide default OPTIONS behaviour unless app.options() is used. Your application or framework may also remove routes by simply by removing them from this object.
Your app.routes should look similar to this:
{ get:
[ { path: '/health/*',
method: 'get',
callbacks: [Object],
keys: []}]
}
So, you should be able to loop through app.routes.get until you find what you are looking for, and then delete it.
The above approach requires you have a named function for the route. I wanted to do this as well but didn't have named functions for routes so I wrote an npm module that can remove routes by specifying the routing path.
Here you go:
https://www.npmjs.com/package/express-remove-route
It is possible to remove mounted handlers (added with app.use) while the server is running, although there is no API to do this, so it isn't recommended.
/* Monkey patch express to support removal of routes */
require('express').HTTPServer.prototype.unmount = function (route) {
for (var i = 0, len = this.stack.length; i < len; ++i) {
if (this.stack[i].route == route) {
this.stack.splice(i, 1);
return true;
};
}
return false;
}
This is something I need, so it's a shame there isn't a proper api, but express is just mimicing what connect does here.
app.get$ = function(route, callback){
var k, new_map;
// delete unwanted routes
for (k in app._router.map.get) {
if (app._router.map.get[k].path + "" === route + "") {
delete app._router.map.get[k];
}
}
// remove undefined elements
new_map = [];
for (k in app._router.map.get) {
if (typeof app._router.map.get[k] !== 'undefined') {
new_map.push(app._router.map.get[k]);
}
}
app._router.map.get = new_map;
// register route
app.get(route, callback);
};
app.get$(/awesome/, fn1);
app.get$(/awesome/, fn2);
And then when you go to http://...awesome fn2 will be called :)
Edit: fixed the code
Edit2: fixed again...
Edit3: Maybe simpler solution is to purge routes at some point and repopulate them:
// remove routes
delete app._router.map.get;
app._router.map.get = [];
// repopulate
app.get(/path/, function(req,res)
{
...
});
You can look into Express route middleware and possibly do a redirect.
As already mentioned above, the new Express API doesn't seem to support this.
Is it really necessary to completely remove the mapping? If all you need is to stop serving a route, you can easily just start returning some error from the handler.
The only (very odd) case where this wouldn't be good enough is if dynamic routes were added all the time, and you wanted to completely get rid of old ones to avoid accumulating too many...
If you want to remap it (either to do something else, or to map it to something that always returns an error), you can always add another level of indirection:
var healthHandler = function(req, res, next) {
// do something
};
app.get('/health/*', function(req, res, next) {
healthHandler(req, res, next);
});
// later somewhere:
healthHandler = function(req, res, next) {
// do something else
};
In my opinion this is nicer/safer than manipulating some undocumented internals in Express.
There is no official method but you can do this with stack.
function DeleteUserRouter(appName){
router.stack = router.stack.filter((route)=>{
if(route.route.path == `/${appName}`){
return false;
}
return true;
});
}
appName is path name .
Filter the methods in the router.route.stack where the router is express.Router
or you can do the same for the app but with app._router.stack.
Note: For below 4.0 use - app.router.stack.

Resources