Anirudh Mittal
Anirudh Mittal

Reputation: 45

Sharing a variable between 2 routes express

I wanted to know if there is a way to share variables between 2 routes in expressJS without declaring it as a global. Consider I have the following routes:

exports.routeOne = (req,res) => { 
 var myVariable='this is the variable to be shared';
}

exports.routeTwo = (req,res) => {
  //need to access myVariable here
}

How can this be done ?

Upvotes: 3

Views: 4102

Answers (3)

jfriend00
jfriend00

Reputation: 708026

For user-specific data that you want to persist from one request to the next, you can't just store data in simple server-side variables because server-side variables are freely shared among all users who make requests of your server.

The usual way to store server-side data that is user-specific is to use a session object. In a nutshell, when a user makes a request, some session middleware (which runs on every request) checks to see if a session cookie exists. If it does not, then one is created. The session cookie servers to uniquely identify that particular user when they make future requests.

Once you have a unique session cookie, the session middleware can create a session object that corresponds with that session cookie. Typically, there is a unique ID in the session cookie that servers as a lookup key for the session object.

Now, whenever that user makes a request of your server, the session middleware will look at the session cookie, get the encrypted session id out of it, decrypt the id, look up the session object that corresponds to that id and then make that session object available to your request handlers, usually in req.session. Your request handlers then have full access to the session object and can add, remove or modify your own properties on that session object.

express-session is common piece of middleware that is used for implementing sessions with nodejs/express. There are plenty of examples for how to use it in the documentation so I won't repeat that all here. Here's one such example in the doc.

By default, express-session uses a memory store (which just means the session objects are kept in memory). This can be fine for simple uses, but it has some limitations and express-session does not recommend it for production use. One major limitation of keeping the sessions in memory is that if the server crashes or restarts, all session data is lost. There are dozens of add-in object stores for express-session, most of which store data more durably such as in a database on disk.

Upvotes: 0

James
James

Reputation: 3239

One of the awesome things about NodeJS is that you can store state in variables. The process that runs your NodeJS server continues to run without restarting for each request that comes in. So any variables you store using GLOBAL.myVarName or variables that you store within the scope of a module (a single JavaScript file) will persist... until the process quits. The process could quit if the server goes down or if an Error or other exception is throw that is not caught. You can set up a process manager to keep it running, but your in memory variables are now lost.

I would recommend using variables that are scoped at a higher level for caching, but if the data is important it should be stored to and read from a database as needed.

Here is an example of your routes.js module. Any variable you declare outside of functions are scoped to this file. In other words, the variables are global to this file. You can read up more on that at https://nodejs.org/dist/latest-v8.x/docs/api/modules.html and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures.

routes.js

let variableScopedToModule = 0

exports.routeOne = (req, res) {
  variableScopedToModule++
}

exports.routeTwo = (req, res) {
  console.log(variableScopedToModule)
}

If it is important that you never loose the variables state, and assuming you are not running the server on multiple processes for load balancing, then you could do something like this:

routes.js

const db = require('./my-db-controller')

let cachedValue

exports.routeOne = async (req, res) {
  if (cachedValue === undefined) cachedValue = await db.getValue()
  cachedValue++
  db.setValue(cachedValue)
}

exports.routeTwo = (req, res) {
  console.log(cachedValue)
}

This second solution is more complex because you'll need to understand promises as well as async and await. Also this solution will not work if you are using a load balencer unless you use something like Redis. Alternatively you can just read and write to the database for each request instead of using in memory caching.

Upvotes: 0

James
James

Reputation: 3239

===============

Note

This answer is answering the wrong question, but it might still be useful for others who also misinterpreted the question like I did, so I'm keeping it here for now.

===============

In order for the variable to exist it would have to first execute routeOne and then execute routeTwo. This is a pretty common scenario with express. To get the details on how this works read up on middleware (http://expressjs.com/en/guide/writing-middleware.html) and understand that each route is middleware.

The common pattern solution here is to add a new property to either the req or res object that stores your variable. Then you tell the route to call the next middleware. The next middleware has access to the same req and res so it also has access to the property and value that you just stored.

There is nothing wrong with this practice as most middleware does it. For example the body-parser middleware (https://www.npmjs.com/package/body-parser).

Here is an example of how your code might run:

routes.js

exports.routeOne = (req,res,next) => { 
 req.myVariable='this is the variable to be shared'
 next()
}

exports.routeTwo = (req,res) => {
  //need to access myVariable here
  console.log(req.myVariable)
}

index.js

const express = require('express')
const routes = require('./routes.js)

const app = express()
app.use(routes.routeOne)
app.use(routes.routeTwo)

app.listen(3000)

Upvotes: 3

Related Questions