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

187,258

Solution 1

Attach your variable to the req object, not res.

Instead of

res.somevariable = variable1;

Have:

req.somevariable = variable1;

As others have pointed out, res.locals is the recommended way of passing data through middleware.

Solution 2

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.

res.locals (Note: the documentation quoted here is now outdated, check the link for the most recent version.)

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();
});

Solution 3

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.

Solution 4

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:


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.

Solution 5

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.

Share:
187,258

Related videos on Youtube

user2791897
Author by

user2791897

Updated on April 20, 2022

Comments

  • user2791897
    user2791897 about 2 years

    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;
    ...
    
    • Andreas Hultgren
      Andreas Hultgren over 10 years
      Should work. Unless it's a typo in the question you probably fail because you assign the value to res in middleware1 and try to get it from req in middleware2.
    • user2791897
      user2791897 over 10 years
      Thankz @AndreasHultgren
    • Ronnie Royston
      Ronnie Royston over 5 years
      Local variables are available in middleware via req.app.locals expressjs.com/pt-br/api.html#app.locals
  • Kousha
    Kousha over 8 years
    How do you suggest to set req.YOUR_APP_NAME = {} initially? You just try to write to req.YOUR_APP_NAME.someVar you will get an error as req.YOUR_APP_NAME is not defined yet.
  • Tomas
    Tomas over 8 years
    @Kousha You can write router middleware at the top of your routing script: router.use(function(req,res,next){req.YOUR_APP_NAME = {};next()})
  • philx_x
    philx_x almost 8 years
    is there a way to pass it as param with the next() function? like next(myObj)
  • cchamberlain
    cchamberlain almost 8 years
    @Kousha - Your undefined error has nothing to do with express, its you trying to assign a property to an object that does not exist. Typically to do this you would use req.APP_NS = req.APP_NS || {}; req.APP_NS.somevar = 'value'.
  • Sam Holmes
    Sam Holmes almost 8 years
    Don't know why this isn't the accepted answer, this is the documented way to set variables from middleware throughout a request.
  • real_ate
    real_ate about 7 years
    res.locals is intended to be used by views that are eventually rendered during the lifecycle of the request, this is what the documentation is saying. If you are not using views it is overkill to put things on the locals object and it is not the convention. In these cases, I tend to encourage people to stick with the convention so that we can reduce cognitive load while learning concepts like Express or request lifecycles.
  • cchamberlain
    cchamberlain about 7 years
    @real_ate that is the primary usage of res.locals, however it doesn't address OPs question. Passing request scoped variables to future middleware is sometimes a necessity, the times I've had it come up is typically around user authentication in an early middleware which sets claims that get routed in a downstream middleware.
  • godzsa
    godzsa about 7 years
    use res.locals.variable = var; see the other answer
  • Merl
    Merl over 6 years
    @philx_x, if you pass any parameter to next function, it will trigger express' error handler and drop out. check the docs.
  • William Wu
    William Wu over 6 years
    to retrieve the variable, use req.res.locals.variable in next middleware function
  • CodyBugstein
    CodyBugstein over 6 years
    And then how to you retrieve the variable in the next middleware call?
  • cchamberlain
    cchamberlain over 6 years
    @CodyBugstein - They should remain on the locals object. Added an example.
  • cchamberlain
    cchamberlain over 6 years
    @WilliamWu its res.locals, not req.res.locals.
  • jasonseminara
    jasonseminara about 6 years
    res.locals.myVar is the way to go.
  • Catfish
    Catfish over 5 years
    The express documentation for writing middleware sets variables on the req object expressjs.com/en/guide/writing-middleware.html. Look at the section Middleware function requestTime
  • cchamberlain
    cchamberlain over 5 years
    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. Mutating request could be dangerous as there are reserved properties and evolving standards.
  • Rob Cannon
    Rob Cannon about 5 years
    It's still valid because there are too many middleware libraries that don't give you the res object. Almost every time I've needed to do this, res.locals was a non-starter. multer and express-http-proxy are two prominent examples. For this reason, I think @real_ate 's comment hits the nail on the head.
  • cchamberlain
    cchamberlain about 5 years
    That's what forks and PRs are for in open source.
  • goonerify
    goonerify over 4 years
    After placing this variable on the response object, it should probably be removed before sending a response back to the client if it's not your intention to return that dataset along with the rest of your payload
  • cchamberlain
    cchamberlain about 4 years
    @goonerify thats luckily not how response works. Responses are transmitted by calling a functional property of the response object such as res.json({}), etc. res.locals is only available on the back-end over the life of the request. expressjs.com/en/5x/api.html
  • Predrag Davidovic
    Predrag Davidovic over 3 years
    Sorry for asking, but now I'm confused. Is this contradictory answer. First you suggested to do it req.somevariable = variable1; and then you suggested to use res.locals. Maybe I missed something, if someone can explain me better?
  • dilantha111
    dilantha111 over 3 years
    @PredragDavidovic had the same issue, but with the other answers it is res.locals what you are looking for. Really should reconsider the selected answer.
  • java-addict301
    java-addict301 over 3 years
    there seems to be contradictory information in this accepted answer
  • Niels Abildgaard
    Niels Abildgaard about 2 years
    Where is res.locals recommended? The API documentation you all keep referring to seems to indicate that the res.locals field is for passing data to views when using res.render. In fact, middleware like express.json() extends req, which seems to contradict the advice given here?
  • Niels Abildgaard
    Niels Abildgaard about 2 years
    I said this on the "marked correct" answer, but I'll add it here, too: Where is res.locals recommended? The API documentation you all keep referring to seems to indicate that the res.locals field is for passing data to views when using res.render. In fact, middleware like express.json() extends req, which seems to contradict the advice given here?
  • Niels Abildgaard
    Niels Abildgaard about 2 years
    Just to be clear, the video doesn't show a solution to what is being asked. The question is about how to pass values from one middleware to another. The video explicitly states that res.locals is for passing values straight to template rendering. (But it's a fine video)
  • cchamberlain
    cchamberlain about 2 years
    @NielsAbildgaard OP wants request scoped local variables that can be accessed across middlewares. An object that contains response local variables scoped to the request - seems pretty clear to me. One of the main reasons you'd use it is to expose things to views. A middleware library like express.json() is about the only use case I could see for arguing in favor of req since they are going to want to avoid collisions with user level variables occupying res.locals. They have unit tests and maintainers. If a future change adds a new field to req and you named your field that..
  • Niels Abildgaard
    Niels Abildgaard about 2 years
    I wrote a whole long answer with data for why res.locals is specifically for res.render and always has been. If you check the linked Github PR you'll see the maintainers agreeing, and that we are clarifying the docs. stackoverflow.com/a/71487552/1080564
  • Niels Abildgaard
    Niels Abildgaard about 2 years
    The documentation has now been updated (c.f. my updated answer, linked in my last comment). I don't want to seem rude by editing your answer, as we seem to disagree on the correct approach, but I think it would make sense to update the documentation you cite to be the current version :-)