Passing variables to the next middleware using next() in Express.js - javascript

I want to pass some variable from the first middleware to another middleware, and I tried doing this, but there was "req.somevariable is a given as 'undefined'".
//app.js
..
app.get('/someurl/', middleware1, middleware2)
...
////middleware1
...
some conditions
...
res.somevariable = variable1;
next();
...
////middleware2
...
some conditions
...
variable = req.somevariable;
...

v4.x API docs
This is what the res.locals object is for. Setting variables directly on the request object is not supported or documented. res.locals is guaranteed to hold state over the life of a request.
Quote from the docs:
An object that contains response local variables scoped to the
request, and therefore available only to the view(s) rendered during
that request / response cycle (if any). Otherwise, this property is
identical to app.locals.
This property is useful for exposing request-level information such as
the request path name, authenticated user, user settings, and so on.
app.use(function(req, res, next) {
res.locals.user = req.user;
res.locals.authenticated = !req.user.anonymous;
next();
});
To retrieve the variable in the next middleware:
app.use(function(req, res, next) {
if (res.locals.authenticated) {
console.log(res.locals.user.id);
}
next();
});

Attach your variable to the res.locals object, not req.
Instead of
req.somevariable = variable1;
Have:
res.locals.somevariable = variable1;
As others have pointed out, res.locals is the recommended way of passing data through middleware.

I don't think that best practice will be passing a variable like req.YOUR_VAR. You might want to consider req.YOUR_APP_NAME.YOUR_VAR or req.mw_params.YOUR_VAR.
It will help you avoid overwriting other attributes.

The most common pattern for passing variables on to other middleware and endpoint functions is attaching values to the request object req.
In your case, that would mean having middlewares such as these:
app.use(function (req, res, next) {
req.someVariable = 123;
next();
});
app.use(function (req, res, next) {
console.log("The variable is", req.someVariable);
next();
});
There are many common use cases of this pattern, and it is the standard way of doing it in the express community. See, for example:
express.json, which ships with express, previously part of body-parser which follows the same pattern for all request parsing.
multer used for parsing multipart data
express-jwt
express-validator (see code)
express-session
express-useragent
express-pino-logger
express-bunyan-logger
It is worth noting that the currently most highly voted answer incorrectly recommends using res.locals for this purpose---which seems to stem from a misreading of the documentation. For that reason, I'll elaborate on why this is not the usual approach to the problem (although it isn't particularly harmful either).
The documentation
As supporting evidence for the res.locals approach being the appropriate one for the case, the now outdated documentation is cited:
An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any). Otherwise, this property is identical to app.locals.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on.
Note the framing here: res.locals is for variables only available "to the view(s) rendered during that request" (emphasis added).
That is what res.locals relates to. res.render renders some template file with some given data as well as access to the locals. This was actually more clear in the v2 docs, and we've now updated the current Express documentation to be clearer:
Use this property to set variables accessible in templates rendered with res.render. The variables set on res.locals are available within a single request-response cycle, and will not be shared between requests.
In order to keep local variables for use in template rendering between requests, use app.locals instead.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on to templates rendered within the application.
(Emphasis added.)
The guide
Further evidence of extending req being the standard approach is found in the guide on Writing Middleware, which states:
Next, we’ll create a middleware function called “requestTime” and add a property called requestTime to the request object.
const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
When this was mentioned in discussion in the answers on this here question, one user responded: "This was the way you'd do it before they added res.locals so might be old docs. res.locals is a namespace specifically for this."
This doesn't track with the history of the codebase, however: locals have been present since v2, which is significantly before e.g. express.json was included in the library, at which point it would have made sense to change the behvaior, if it was indeed correct to save values in res.locals.
Closing notes
Shoutout to #real_ate who wrote in the comments, but was overlooked.

That's because req and res are two different objects.
You need to look for the property on the same object you added it to.

The trick is pretty simple... The request cycle is still pretty much alive. You can just add a new variable that will create a temporary, calling
app.get('some/url/endpoint', middleware1, middleware2);
Since you can handle your request in the first middleware
(req, res, next) => {
var yourvalue = anyvalue
}
In middleware 1 you handle your logic and store your value like below:
req.anyvariable = yourvalue
In middleware 2 you can catch this value from middleware 1 doing the following:
(req, res, next) => {
var storedvalue = req.yourvalue
}

As mentioned above, res.locals is a good (recommended) way to do this. See here for a quick tutorial on how to do this in Express.

Related

Is there a way in Node.js to create global variables that live only for the lifetime of the request? [duplicate]

I want to pass some variable from the first middleware to another middleware, and I tried doing this, but there was "req.somevariable is a given as 'undefined'".
//app.js
..
app.get('/someurl/', middleware1, middleware2)
...
////middleware1
...
some conditions
...
res.somevariable = variable1;
next();
...
////middleware2
...
some conditions
...
variable = req.somevariable;
...
v4.x API docs
This is what the res.locals object is for. Setting variables directly on the request object is not supported or documented. res.locals is guaranteed to hold state over the life of a request.
Quote from the docs:
An object that contains response local variables scoped to the
request, and therefore available only to the view(s) rendered during
that request / response cycle (if any). Otherwise, this property is
identical to app.locals.
This property is useful for exposing request-level information such as
the request path name, authenticated user, user settings, and so on.
app.use(function(req, res, next) {
res.locals.user = req.user;
res.locals.authenticated = !req.user.anonymous;
next();
});
To retrieve the variable in the next middleware:
app.use(function(req, res, next) {
if (res.locals.authenticated) {
console.log(res.locals.user.id);
}
next();
});
Attach your variable to the res.locals object, not req.
Instead of
req.somevariable = variable1;
Have:
res.locals.somevariable = variable1;
As others have pointed out, res.locals is the recommended way of passing data through middleware.
I don't think that best practice will be passing a variable like req.YOUR_VAR. You might want to consider req.YOUR_APP_NAME.YOUR_VAR or req.mw_params.YOUR_VAR.
It will help you avoid overwriting other attributes.
The most common pattern for passing variables on to other middleware and endpoint functions is attaching values to the request object req.
In your case, that would mean having middlewares such as these:
app.use(function (req, res, next) {
req.someVariable = 123;
next();
});
app.use(function (req, res, next) {
console.log("The variable is", req.someVariable);
next();
});
There are many common use cases of this pattern, and it is the standard way of doing it in the express community. See, for example:
express.json, which ships with express, previously part of body-parser which follows the same pattern for all request parsing.
multer used for parsing multipart data
express-jwt
express-validator (see code)
express-session
express-useragent
express-pino-logger
express-bunyan-logger
It is worth noting that the currently most highly voted answer incorrectly recommends using res.locals for this purpose---which seems to stem from a misreading of the documentation. For that reason, I'll elaborate on why this is not the usual approach to the problem (although it isn't particularly harmful either).
The documentation
As supporting evidence for the res.locals approach being the appropriate one for the case, the now outdated documentation is cited:
An object that contains response local variables scoped to the request, and therefore available only to the view(s) rendered during that request / response cycle (if any). Otherwise, this property is identical to app.locals.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on.
Note the framing here: res.locals is for variables only available "to the view(s) rendered during that request" (emphasis added).
That is what res.locals relates to. res.render renders some template file with some given data as well as access to the locals. This was actually more clear in the v2 docs, and we've now updated the current Express documentation to be clearer:
Use this property to set variables accessible in templates rendered with res.render. The variables set on res.locals are available within a single request-response cycle, and will not be shared between requests.
In order to keep local variables for use in template rendering between requests, use app.locals instead.
This property is useful for exposing request-level information such as the request path name, authenticated user, user settings, and so on to templates rendered within the application.
(Emphasis added.)
The guide
Further evidence of extending req being the standard approach is found in the guide on Writing Middleware, which states:
Next, we’ll create a middleware function called “requestTime” and add a property called requestTime to the request object.
const requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
When this was mentioned in discussion in the answers on this here question, one user responded: "This was the way you'd do it before they added res.locals so might be old docs. res.locals is a namespace specifically for this."
This doesn't track with the history of the codebase, however: locals have been present since v2, which is significantly before e.g. express.json was included in the library, at which point it would have made sense to change the behvaior, if it was indeed correct to save values in res.locals.
Closing notes
Shoutout to #real_ate who wrote in the comments, but was overlooked.
That's because req and res are two different objects.
You need to look for the property on the same object you added it to.
The trick is pretty simple... The request cycle is still pretty much alive. You can just add a new variable that will create a temporary, calling
app.get('some/url/endpoint', middleware1, middleware2);
Since you can handle your request in the first middleware
(req, res, next) => {
var yourvalue = anyvalue
}
In middleware 1 you handle your logic and store your value like below:
req.anyvariable = yourvalue
In middleware 2 you can catch this value from middleware 1 doing the following:
(req, res, next) => {
var storedvalue = req.yourvalue
}
As mentioned above, res.locals is a good (recommended) way to do this. See here for a quick tutorial on how to do this in Express.

Making route unique to one ejs file

i want a URL like this localhost3000/hh234due, with a unique id, to route to specific page, but with what am doing it is conflicting with other routes.
how to make /:id unique to one view
module.exports = function (app) {
app.get('/:id', function (req, res) {
res.render('page/index');
});
}
Since routes are tested in order, place it last in the sequence and anything it would conflict with will take precedence over it.
In general, this is just a questionable practice because
app.get('/:id', ...)
matches every single possible top level route and invites conflicts with other top level routes that you want/need in the workings of your site.
You can make it work by always placing it as the last possible route definition, but I would recommend changing the URL to something like
http://localhost:3000/id/hh234due
and then you can use:
app.get('/id/:id', ...)
and not have any conflicts with any of your other top level routes.
When doing it this way, the URL structure is more declarative too since the /id part clearly states what this URL is rather than before where you were more relying on the fact that it doesn't look like any of the other top level routes on your site so "I guess" it must be an id which is not as declarative or clear to the other developers that might work on this site some time in the future.
It should be enough to put the spcific page routing before the general one, like this:
module.exports = function (app) {
app.get('/hh234due', function (req, res) {
res.render('<your special page>');
});
app.get('/:id', function (req, res) {
res.render('page/index');
});
}

req.flash() returning an empty object in app.js but works fine in a controller method

So i am setting my flash messages inside my controller method like this:req.flash('info', 'flash is working') and then i console.log(req.flash()) in the controller to see if it works. Then in my app.js file i simply pass it on to a res.locals so that it is available to me in my templates but there i was receiving an empty object so i did console inside the middleware to assign res.locals and it was empty there as well. Why is this happening ?
app.use((req, res, next) => {
res.locals.flashes = req.flash();
res.locals.h = helpers;
console.log(req.flash());
next();
});
btw i know the first request is supposed to return empty flash object but the second one returns empty as well
Alright, i made a stupid mistake with the order of requiring the session module and because of that sessions were not working properly and i was getting an empty object in response as the flash messages were not really getting stored in the session. Fixing the order of modules fixed it for me.

What's the purpose of using ":" before a name in the path of a URL?

This might seem a trivial problem, but I have searched for a while for a concrete authoritative answer, but nothing came out so far.
I have been using express.js, and I have been seeing URLs' handlers with paths such as
app.get("/users/:id", function(req, res) {
res.send(req.params)
})
or
app.get("/users/:name/photos", function(req, res) {
res.send(req.params)
})
But I am not completely sure of the purpose of using : before id (or name) in those cases.
I know that, if I use : before id, id will be available as parameter of req.params, i.e. req.params.id. Usually id is an integer, but this is actually not strictly necessary, it could be anything else (e.g. string).
My guess about the reason of using : before a name in the path of a URL is simply to say to express that instead of :id or :name, we can pass whatever we want of any type. :id or :name are considered variables. Is this guess correct?
What are the purposes of using : when handling routing? When should we use it?
The : just indicates a named variable as a placeholder in that part of the url. Without it, id would get matched literally in the url and would not be interpreted as a dynamic placeholder. That's all there is to it.
You are right.
: is just used to set a route. It could have been a ! or # or anything else for that matter. It declares a variable in route.
In your code:
app.get("/users/:id", function(req, res) {
res.send(req.params)
})
/users/:id becomes a route. It means anything after users/ will be caught by this handler and become available in the id variable inside it. It doesn't have to be an integer.
Here:
app.get("/users/:name/photos", function(req, res) {
res.send(req.params)
})
The route is defined something like this:
/users/john/photos/
In this case, john is a variable which matched the route set.

Express.js View "globals"

I'm using Express.js (on Node.js) and I know that you can render a view with custom data via the "locals" parameter. (res.render("template", { locals: { foo: "bar" } });)
Is there any way to have "globals"? (ie. data that's accessible to every view)
I saw view options, but that isn't recursive, so it replaces the locals I set if I use any locals with my template.
This is my use case: I want to make it so that CSS/JS files can be added on a per-page basis, and that is part of my main layout. The problem is, if I don't explicitly set those arrays on every render, I get an undefined error, so in my template I always have to do the typeof css !== "undefined" dance. Additionally, I have other select box option lists that I don't want to have to explicitly add to each of my forms.
It's worth noting for those who may have come across this question since the release of Express 3, that the method 'dynamicHelpers' no longer exists.
Instead you can use the app.locals function, which acts as an object you can store values or functions in, and then makes them available to views. For example:-
// In your app.js etc.
app.locals.title = "My App";
app.locals({
version: 3,
somefunction: function() {
return "function result";
}
});
// Then in your templates (shown here using a jade template)
=title
=version
=somefunction()
// Will output
My App
3
function result
If you need access to the request object to pull information from, you can write a simple middle-ware function and use the app.settings variable.
For example, if you are using connect-flash to provide messages to your users, you might do something like this:
app.use(function(req, res, next) {
app.set('error', req.flash('error'));
next();
});
Which would give you access to the error message with =settings.error in your template.
These topics are covered here, albeit slightly briefly: http://expressjs.com/api.html#app.locals
Update: Express 4
app.locals is now a simple JavaScript Object, so every property has to be set one by one.
app.locals.version = 3;
app.locals.somefunction = function() {
return "function result";
}
res.locals provides the exact same functionality, except it should be used for request-specific data rather than application-wide data. A user object or settings is a common use case.
res.locals.user = req.isAuthenticated() ? req.user : null;
res.locals.userSettings = {
backgroundColor: 'fff'
}
There is a way to have "global" variables for views, using dynamic view helpers.
From the Express.js guide:
app.dynamicHelpers(obj)
Registers dynamic view helpers.
Dynamic view helpers are simply
functions which accept req, res, and
are evaluated against the Server
instance before a view is rendered.
The return value of this function
becomes the local variable it is
associated with.
app.dynamicHelpers({ session:
function(req, res){
return req.session; } });
All views would now have session
available so that session data can be
accessed via session.name etc:
You can find a real example on how to use them here: https://github.com/alessioalex/Nodetuts/tree/master/express_samples (node app.js to start the app)
A real-world example of using view options as the author mentioned:
var app = express.createServer();
app.configure(function() {
app.set('views', path.join(__dirname, '..', 'views'));
app.set('view engine', 'jade');
app.set('view options', {
assetVersion: 1
});
And then in my layout.jade (base template for the app in my case):
link(rel='stylesheet', href='/static/css/' + assetVersion + '/style.css')
script(src='/static/js/' + assetVersion + '/script.js')
With this little trick, I only have to update the assetVersion variable one place to make sure that my assets aren’t cached in Varnish or other places.
I wound up looking into the source code, and I've actually found that this is now possible in never versions of Express. (so far, only available through GitHub)
The simplest way to accomplish this is to create a variable that represents the default set of locals for your views. Then create a function that accepts an object, merges it with the locals, and returns the merged object.
I also pass ALL my locals inside a container object i.e. {locals:{g:{prop:val}}} so in my views I can refernce g.prop which will just return null when it isn't set, instead of throwing an undefined error.
function default_page_vars(custom_vars){
var vars = {
footer: true,
host: req.headers.host.split(':')[0],
config: this.config
};
if(custom_vars){
for(var k in custom_vars){
vars[k] = custom_vars[k];
}
}
return {
g:vars
};
}
//within your handler
response.render(view, {
locals: default_page_vars(other_locals)
});
This is a buried response, but I finally got it to work.
1) This is an example around the module connect-flash
2) Add a piece of middleware in server.js/app.js to add req to locals. This allows the template to call request.flash() whenever it needs. Without this, flash() gets consumed on each request/redirect defeating the purpose.
var app = module.exports = express()
, flash=require('connect-flash');
app.configure(function(){
...
app.use(express.session({ secret: "shhh" }));
// Start Router
app.use(flash());
app.use(function(req, res, next) {
res.locals.request = req;
next();
});
app.use(app.router);
});
3) Setup your route as normal (this is coffeescript, but nothing special)
app.get '/home', (req, res) ->
req.flash "info", "this"
res.render "#{__dirname}/views/index"
4) Call request.flash() when you want the messages. They are consumed on each call, so don't console.log them or they'll be gone :-)
!!!
html
head
title= config.appTitle
include partials/_styles
body
include partials/_scripts
#header
a(href="/logout") Logout CURRENTUSER
h2= config.appTitle
#messages
- var flash = request.flash()
each flashType in ['info','warn','error']
if flash[flashType]
p.flash(class=flashType)
= flash[flashType]
block content
h1 content here
Express 4
You can access local variables in templates rendered within the application.
So, if you want to use any locals in your template => assuming you have a template engine npm installed to your node/express application.
First, you need to set the express locals objects with your custom variables in your app.js file, you can use an object if multiple values are needed (our case in this post)
/**
* Set locals object
*/
app.locals.layoutData = {
site: {
title: 'MyWebSiteTitle',
},
metaTag: {
charset: 'UTF-8',
description: 'MyDescription',
keywords: 'keyword-1,keyword-2,...',
author: 'MyName',
viewport: 'width=device-width, initial-scale=1.0'
}
};
Then, to access the values in the template file layout.pug (in the case of PUG template engine for instance)
doctype html
html
head
//title
title #{locals.layoutData.site.title}
//Describe metadata
meta(charset=layoutData.metaTag.charset)
meta(name='description', content=locals.layoutData.metaTag.description)
meta(name='keywords', content=locals.layoutData.metaTag.keywords)
meta(name='author', content=locals.layoutData.metaTag.author)
meta(name='viewport', content=locals.layoutData.metaTag.viewport)
body
block content
br
hr
footer
p All rights reserved © 2018 | #{locals.layoutData.site.title}
Tested with
"dependencies": {
"express": "^4.16.3",
"pug": "^2.0.3"
}

Categories