Node.js Express3 - Middleware to add render data to all render requests - node.js

Is it possible through express middleware or another method to add render data (the second option in res.render) to each call in the apps routes.
My app is using passport for authentication and I would like a middleware to always append the user information to each rendered template.
Currently each of my calls to res.render look similar to. I would like to remove the user : req.user and add that to a middleware function.
// Page 1
res.render("somepage1",{data : "somepage1", user : req.user});
// Page 2
res.render("somepage2",{data : "somepage2", user : req.user});

Express does provide app.locals and res.locals, which it automatically merges with explicit locals passed in to render by a route handler.
app.use(function(req, res, next) {
res.locals.user = req.user;
next();
});
Alternatively, you could hot patch the render function. I'd avoid this since it's extra overhead, but if for some reason you needed to pass information not available before your route handler runs, it's an option:
app.use(function(req, res, next) {
var render = res.render;
res.render = function(view, locals, cb) {
if (typeof locals == 'object') locals.user = req.user;
render.call(res, view, locals, cb);
};
next();
});

Figured it out.
You can use locals in your middleware.
app.use(function(req, res, next){
res.locals.user = req.user;
next();
});
Then in the templates use.
<h1>User Name:{{user.name}}</h1>
<h1>User Name:{{_locals.user.name}}</h1>

Related

A middleware containing res.locals is not working

Hi I am using this given middleware to show username userid etc on every template but this middleware is not working neither console.log working nor locals working in my ejs template. Please check why!
I am using this middleware in the last before app.listen.
app.use(function(req, res, next) {
console.log("Hello");
res.locals.username = req.session.username;
res.locals.userid = req.session.userid;
res.locals.w_id = req.session.w_id;
next();
});
I am using this middleware in the last before app.listen.
That's your issue, you must add this middleware before all the routes so that it will be called.

How to handles parameters in nested routes in express js?

I have been experimenting with nested routes as they are convenient in passing on variables
router.post('/postlinkone', function(req, res, next){
//define few variables (x,y)
//render or redirect to close this route
router.post('/postlinktwo', function(req, res, next){
//use (x,y)
//render or redirect
}
}
The problem is that express is able to pass on the variables (x,y) during initialization to postlinktwo however these variables are not refreshed in next cycles. Is there a way to hard refresh them or is there a easier way to pass variables
Express has the philosophy of building on the req object.
Instead of nesting routes, have independent routes that modify req, altering stuff that you want.
router.get('/routeOne', function(req, res, next) {
// do something
req._data = {};
req._data.x = 'bla bla';
// call next to move to the next route middleware
next();
});
router.get('/routeOne', function(req, res, next) {
// check if the params are still there.
console.log(req._data);
});

Using Express 4 how to redirect to my own route without losing req and response data?

I have my application structured with 3 Routes (api, admin, default). Each lives in there own file and has it's own middleware and exports a Route. The problem I am facing is when I want to forward to another route that lives on a different router. Essentially I want to call the same function so that I am not serving up the same view from multiple locations.
I don't want to user res.redirect('/someplace') because I want to be able to pass the req and res objects on to the method.
|-app.js
|-routes
|---admin.js
|---api.js
|---default.js
The routes are required and used in app.js as follows
app.use('/api', require('./routes/api')(passport);
app.use('/admin', require('./routes/admin')(passport);
app.use('/', require('./routes/default')(passport);
Inside of admin if have a situation where I need redirect to login and pass some data
// authenticates all routes for the admin router
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.flashMessage.push('Session expired'); //is lost after redirect
res.redirect('/login');
//do I need to restructure my whole app so that I don't
//have to call res.redirect('login')
});
Any ideas on how to structure this? Do I need to export every method and keep all of my routes in one router file? That doesn't very clean, but if the functions are somewhere else it may be too messy.
You can forward it by calling the next callback ,but only if you do not use any paths.
app.use(function(req, res, next) {
// ... api
next();
});
app.use(function(req, res, next) {
// ... admin
next();
});
Another option is use * that will match all paths:
app.use("*", function(req, res, next) {
var path = req.path; // just example how it can be done
if (path === "/api") {
// ...
path = "/admin";
}
if (path === "/admin") {
// ...
}
});
Edit:
I don't think that express has something like next('/login'); ,so basically function that can forward a request to another path and I don't think that is right to have something like this. If a client ask for /admin you should send this particular page and not the page that is under /login. If you want to send back to a client the login page than just redirect it as you did it in your question. I understand that you want to keep the req, res ,but then is the problem in the proposal/structure of your webapp.

Node.js matching the url pattern

I need an equivalent of following express.js code in simple node.js that I can use in middleware. I need to place some checks depending on the url and want to do it in a custom middleware.
app.get "/api/users/:username", (req,res) ->
req.params.username
I have the following code so far,
app.use (req,res,next)->
if url.parse(req.url,true).pathname is '/api/users/:username' #this wont be true as in the link there will be a actual username not ":username"
#my custom check that I want to apply
A trick would be to use this:
app.all '/api/users/:username', (req, res, next) ->
// your custom code here
next();
// followed by any other routes with the same patterns
app.get '/api/users/:username', (req,res) ->
...
If you only want to match GET requests, use app.get instead of app.all.
Or, if you only want to use the middleware on certain specific routes, you can use this (in JS this time):
var mySpecialMiddleware = function(req, res, next) {
// your check
next();
};
app.get('/api/users/:username', mySpecialMiddleware, function(req, res) {
...
});
EDIT another solution:
var mySpecialRoute = new express.Route('', '/api/users/:username');
app.use(function(req, res, next) {
if (mySpecialRoute.match(req.path)) {
// request matches your special route pattern
}
next();
});
But I don't see how this beats using app.all() as 'middleware'.
You can use node-js url-pattern module.
Make pattern:
var pattern = new UrlPattern('/stack/post(/:postId)');
Match pattern against url path:
pattern.match('/stack/post/22'); //{postId:'22'}
pattern.match('/stack/post/abc'); //{postId:'abc'}
pattern.match('/stack/post'); //{}
pattern.match('/stack/stack'); //null
For more information, see: https://www.npmjs.com/package/url-pattern
Just use the request and response objects as you would in a route handler for middleware, except call next() if you actually want the request to continue in the middleware stack.
app.use(function(req, res, next) {
if (req.path === '/path') {
// pass the request to routes
return next();
}
// you can redirect the request
res.redirect('/other/page');
// or change the route handler
req.url = '/new/path';
req.originalUrl // this stays the same even if URL is changed
});

Pass req variables from .param to .use?

The code below demonstrates trying to log req.hash_id from middleware. It's showing up for me as undefined. Is there anyway that I can get this to work? Or easily parse ":hash" out in regular .use middleware?
app.param("hash",function(req, res, next, id){
req.hash_id = id;
return next();
});
app.use(function(req, res, next){
console.log(req.hash_id);
return next();
});
I don't think you can use req.params inside a middleware function as it is bound to specific routes. You could use req.query though, but then you have to write your routes differently, e.g. /user?hash=12345abc. Not sure about passing the value from app.param to app.use.
If you have a specific structure for your routes, like /user/:hash you could simply write
// that part is fine
app.param('hash',function(req, res, next, id){
req.hash_id = id;
return next();
});
app.all('/user/:hash', function(req, res, next) { // app.all instead app.use
console.log(req.hash_id);
next(); // continue to sending an answer or some html
});
// GET /user/steve -> steve

Resources