node js - are modules shared between users? - node.js

Given the following module:
module.exports = function() {
var env;
var module = {};
module.setEnv= function(myEnv) {
env = myEnv; // env may be set to a different value per user
}
module.doActionWithEnv = function() {
...
}
...
return module;
}
I require the module like so:
var myModule = require('/myModule')();
Now my question is, is my module shared between 2 different users that visit the site? By that I mean, can collisions occur if one user sets the private env variable, and then the other calls some function inside the module that depends on env and thus gets the wrong result?
Thanks.

Variables on your server are generally once per server process, not once per user making a request. Some variables like the req and res objects passed to a request handler are uniquely created for each request. Per user variables will typically need some sort of session management layer to allow the server to identify which user is making the request and to then access data stored for that specific user. You can read Express Sessions or Node.js and Express Sessions or Express.js Sessions – A Detailed Tutorial for more info about using sessions in Express and there are a number of NPM modules for implementing sessions with Express though express-session is likely the most popular.
To explain about your code, in this line of your code:
var myModule = require('/myModule')();
You will get a new myModule for every call to that. So, each time you call that module constructor, you get a new myModule object that has a new env inside of it.
But, if you just call that constructor once and have only one myModule variable in your code and multiple requests from your web server on behalf of different users are all using that same myModule variable, then they will all be sharing the same myModule object and thus the same env variable inside of it.
What makes your situation a bit confusing is that modules in node.js that are created when you do require('/myModule') are cached and shared in node.js. So, there is only one actual myModule.js loaded module as far as the node.js system is concerned. But, each time you call the module constructor, your own code creates a new object (which you also named module which makes things confusing). So, if you call that constructor 5 times such as:
var m = require('/myModule');
var x1 = m();
var x2 = m();
var x3 = m();
var x4 = m();
var x5 = m();
Or even:
var x1 = require('/myModule')();
var x2 = require('/myModule')();
var x3 = require('/myModule')();
var x4 = require('/myModule')();
var x5 = require('/myModule')();
Then, you will have 5 separate objects in the variables x1 through x5 and each will have their own env variables inside.
But, if you just do this once:
var myObj = require('/myModule')();
myObj.setEnv("hello");
And, then multiple request handlers all refer to that myObj object like this:
app.get('/request1', function(req, res) {
myObj.setEnv("goodbye");
}};
app.get('/request2', function(req, res) {
myObj.setEnv("adios");
}};
Then, both of these request handlers will be operating on the same myObj object no matter what user initiates the request.
How can I avoid this problem then?
If you want per-user information stored on your server, then you would typically use sessions. While there are many ways to implement a session, they usually set a unique cookie for each user's browser when they first visit your site. There is then a storage mechanism on the server that can access data that belongs to the user with that cookie value. You don't use normal JS variables for storing each user's state. You would typically use either an object lookup (by cookie ID) or some sort of database.
Since it looks like you are using Express, there are several NPM modules that will hook into Express and implement sessions for you. The most popular session implementation for Express is express-sessions.

Related

Node/Express - User/session variables

I am attempting to prototype a user journey in Node. The prototype will be used by several testers in parallel.
How can I define and store variables via the routing file that are only accessible by the user on that session?
e.g.
router.post('/thepage', (req, res) => {
passedInfo = req.body
dataObj.incomeWork = passedInfo['work']
dataObj.incomeRent = passedInfo['rent']
dataObj.incomeOther = passedInfo['other-income']
res.render(`/thepage`, dataObj )
}
I've looked a the express-session module, but that requires the variable to be passed from route to route to sustain its values.

Instantiate node module differently per (web) user

I was wondering what the best practice is for the following scenario:
I am planning to use an npm module for a web servie, where the user enters a access and secret key. Then a module is used which is instantiated like this:
var module = require('module')('ACCESS_KEY','SECRET_KEY');
Each user of course has a different access and secret key. The module exposes several functions which I want to use with the user's access and secret key on his behalf.
Now my question is, how I can 'require' that module with the keys from the database for each user, not just for the whole application with a single static pair. I am on node 8 and using ES6.
The crucial detail here is that this:
var module = require('module')('ACCESS_KEY','SECRET_KEY');
...is equivalent to this:
var moduleFunc = require('module');
var module = moduleFunc('ACCESS_KEY', 'SECRET_KEY');
In other words, 'module' exports a function, and you're calling that function with two arguments ('ACCESS_KEY', 'SECRET_KEY') and assigning the result to module.
That means you can instead require('module') at the top of your file and then use the function it gives you as many times as you want later on, with different arguments.
For example:
const someApi = require('some-api');
// ...later...
app.get('/', (req, res) => {
const { ACCESS_KEY, SECRET_KEY } = getUserKeys(req);
const apiClient = someApi(ACCESS_KEY, SECRET_KEY);
// ...
});

Two way communication between routers within express app

I have an express app that has a router for different sections of my application, each contained within individual files. At the end of each file I export the router object like so.
var express = require("express");
var router = express.Router();
//routing handlers
module.exports = router;
However my problem is that I am trying to implement a feature were a user is allowed to edit a post that could be displayed on the front page, therefore in order to have the most current version of the user's post I need to be able to know when the user edits the post to make the necessary changes.
I have two modules one that handles dispatching the user's posts call this module B and another that handles editing call this module A. I need to be able to have module A include handler function and an array from module B, but I also need module B to be able to be notified when to make changes to the its array that module A requires.
I have tried
module A
var express = require('express');
var EventEmitter = require('events').EventEmitter;
var evt = new EventEmitter();
var router = express.Router();
var modB = require('moduleB');
router.evt = evt;
module.exports = router;
Module B
var express = require('express');
var router = express.Router();
var modA = require('moduleA').evt;
modA.on('myEvent',handler);
var myArray = [....];
router.myArray = myArray;
module.exports = router;
This gives me an undefined for modA and throws an error. I suspect it might be the order the modules are included but anyhow I would like to obtain some feedback since I sense that this might not even be good practice.
I think you are running into a common scenario for someone just starting out with express. A lot of people stick everything into routes/controllers when really the route should be very simple and just extract the data needed to figure out what the request is doing and then pass it to a service for most of the processing.
The solution is to create a Service and put the bulk of your logic and common code there, then you can wire up ModA and ModB to use the Service as needed.
EDIT with an example(not working but should give you a good starting point):
Shared Service
var EventEmitter = require('events').EventEmitter;
var evt = new EventEmitter();
module.exports = {
saveData: function(data) {
// do some saving stuff then trigger the event
evt.emit('myEvent', data);
},
onDataChange: function(handler) {
evt.on('myEvent', handler);
}
};
Module A
var service = require('SharedService.js');
// listen for events
service.onDataChange(function(e, data) {
// do something with the data
});
Module B
var service = require('SharedService.js');
// save some data which will cause Module A's listener to fire
service.saveData(data);
This example above hides the implementation of EventEmitter which may or may not be desirable. Another way you could do it would be to have SharedService extend EventEmitter, then your Modules could listen/emit directly on the service.

Explain to Mean.io beginner how Mean.io sample package's authentication works

I'm learning mean.io from this tutorial video, which shows the example package (created by mean package mymodule. It is also described under "Packages" on the docs). I would like help in understanding how the given authentication/authorization works.
The default sample package/module has a simple user authentication that on the client side
myapp/packages/mymodule/public/views/index.html contains:
<li>
Server route that anyone can access
</li>
<li>
Server route that requires authentication
</li>
<li>
Server route that requires admin user
</li>
On the server side,
myapp/packages/mymodule/server/routes/mymodule.js, contains:
// The Package is past automatically as first parameter
module.exports = function(Mymodule, app, auth, database) {
app.get('/mymodule/example/anyone', function(req, res, next) {
res.send('Anyone can access this');
});
app.get('/mymodule/example/auth', auth.requiresLogin, function(req, res, next) {
res.send('Only authenticated users can access this');
});
app.get('/mymodule/example/admin', auth.requiresAdmin, function(req, res, next) {
res.send('Only users with Admin role can access this');
});
...
};
The magic of the different authentication relies on the second argument of app.get() with additional authentication callback: none, auth.requiresLogin, or auth.requiresAdmin.
This is the authentication magic (also on github):
myapp/packages/access/server/config/authorization.js:
/**
* Generic require login routing middleware
*/
exports.requiresLogin = function(req, res, next) {
if (!req.isAuthenticated()) {
return res.send(401, 'User is not authorized');
}
next();
};
/**
* Generic require Admin routing middleware
* Basic Role checking - future release with full permission system
*/
exports.requiresAdmin = function(req, res, next) {
if (!req.isAuthenticated() || !req.user.hasRole('admin')) {
return res.send(401, 'User is not authorized');
}
next();
};
QUESTION A: Why is it "exports.requiresLogin" and "exports.requiresAdmin" in the authorization.js instead of "somethingelse.requiresLogin" and "somethingelse.requiresAdmin"? Is this "exports" related to the myapp/packages/access/server/config/passport.js's exports: module.exports = function(passport) { ...}, github? If so, in what circumstances can we use this "exports"?
Since authentication's authorization rules is written up in package "access" and used in package "mymodule", Mean.io packages are not independent of each other. The Access package is registered on
myapp/packages/access/app.js, github:
var mean = require('meanio'),
Module = mean.Module,
passport = require('passport');
var Access = new Module('access');
Access.register(function(database) {
// Register auth dependency
var auth = require('./server/config/authorization');
require('./server/config/passport')(passport);
// This is for backwards compatibility
mean.register('auth', function() {
return auth;
});
mean.register('passport', function() {
return passport;
});
Access.passport = passport;
Access.middleware = auth;
return Access;
});
QUESTION B: Does Mean.io automatically link all the packages or is there code to link packages somewhere? Is it linked due to the part with "This is for backwards compatibility" shown below? If so, where can "auth" be used? All the packages myapp/packages/? How about in the mean.io base app directory myapp/?
var auth = require('./server/config/authorization');
// This is for backwards compatibility
mean.register('auth', function() {
return auth;
});
QUESTION C: Why is it "Access.passport = passport;", but "middleware" for "Access.middleware = auth;"? What what happen if it were "Access.auth = auth"?
REGARDING QUESTION A (on the use of exports)
In Node.js, assigning values to the exports object makes those values available to the code that requires the source file.
For example, given file foo.js:
exports.foo = "FOO";
exports.bar = "BAR";
and file main.js:
var foo = require('foo.js');
console.log('foo=',foo.foo,'; bar=',foo.bar);
running node main.js will output foo= FOO ; bar= BAR.
See, for example, Node's module documentation or this write-up on require and exports.
REGARDING QUESTION B (on package "linking")
The answer to this question is the complement to the answer to Question A.
There is code to "link" the packages. It is the require statement.
In your app.js source code, the first line (reading var mean = require('meanio')) will set the local variable mean to whatever values are assigned to exports object is when meanio.js and/or the meanio module is loaded.
Same with passport = require('passport'). In that case, the local variable passport will be equal to the value of exports after index.js in the passport module is loaded.
REGARDING QUESTION C
I'm not entirely sure what you are asking here, but let me take a stab at it.
In this case:
1) var mean = require('meanio') in line 1 "imports" the meanio module, such that the local variable mean is more or less set equal to the value of exports in the meanio module.
2) Module = mean.Module in line 2 sets the local variable Module equal to the value of mean.Module, which must have been assigned in the meanio module.
3) var Access = new Module('access') is instantiating an instance of the Module class, assigning it to the local variable Access.
4) Access.passport = passport assigns the instance variable named passport within the instance of meanio.Module named Access (to the value of the passport module required on line #3)
5) Access.middleware = auth assigns the instance variable named middleward within the instance of meanio.Module named Access (to the value returned by require('./server/config/authorization') in line 11).
I'm not familiar with the "meanio" module, but based on this code it looks like you are configuring the meanio.Module("access") instance (named Access) by assigning specific "magic" variable names.
In other words, rather than Access.passport = passport; Access.middleware = auth you might have Access.setPassport(passport); Access.setMiddleware(auth) or (rather than line 5) var Access = new Module('access',passport,auth).
That is, the author of the "meanio" module seems to have decided to use special variable names to configure the class rather than "setter" methods or parameters passed to the constructor. I assume that somewhere in the meanio code you'll find a reference to something like this.middleware and this.passport, where the code is assuming you have "filled in" those instance variables as happens in the last few lines in your code sample.
If you were to add Access.auth = auth then all that would happen is that the Access object would have a new attributed named auth whose value is equal to the that of the local variable auth.
If you used Access.auth instead of Access.middleware, I assume whatever code in the Access class that is using this.middleware will fail, since no value was ever assigned to Access.middleware and Access.auth is not one of the "magic" variable names that meanio is looking for.

Using Express.js 3 with database modules, where to init database client?

Knowing that Express.js pretty much leaves it to developer on deciding app structure, and after reading quite a few suggestions on SO (see link1 and link2 for example) as well as checking the example in official repo, I am still not sure if what I am doing is the best way forward.
Say I am using Redis extensively in my app, and that I have multiple "models" that require redis client to run query, would it be better to init redis client in the main app.js, like this:
var db = redis.createClient();
var models = require('./models')(db);
var routes = require('./controllers')(models);
or would it be better to just init redis in each model, then let each controller require models of interests?
The latter approach is what I am using, which looks less DRY. But is passing models instance around the best way? Note that I am loading multiple models/controllers here - I am not sure how to modify my setup to pass the redis client correctly to each models.
//currently in models/index.js
exports.home = require('./home.js');
exports.users = require('./user.js');
TL;DR, my questions are:
where best to init redis client in a MVC pattern app?
how to pass this redis client instance to multiple models with require('./models')(db)
Update:
I tried a different approach for index.js, use module.exports to return an object of models/controllers instead:
module.exports = function(models){
var routes = {};
routes.online = require('./home.js')(models);
routes.users = require('./user.js')(models);
return routes;
};
Seems like a better idea now?
Perhaps it's useful if I share how I recently implemented a project using Patio, a SQL ORM. A bit more background: the MVC-framework I was using was Locomotive, but that's absolutely not a requirement (Locomotive doesn't have an ORM and it leaves implementing how you handle models and databases to the developer, similar to Express).
Locomotive has a construct called 'initializers', which are just JS files which are loaded during app startup; what they do is up to the developer. In my project, one initializer configured the database.
The initializer established the actual database connection, also took care of loading all JS files in the model directory. In pseudocode:
registry = require('model_registry'); // see below
db = createDatabaseConnection();
files = fs.readDirSync(MODEL_DIRECTORY);
for each file in files:
if filename doesn't end with '.js':
continue
mod = require(path.join(MODEL_DIRECTORY, filename));
var model = mod(db);
registry.registerModel(model);
Models look like this:
// models/mymodel.js
module.exports = function(db ) {
var model = function(...) { /* model class */ };
model.modelName = 'MyModel'; // used by registry, see below
return model;
};
The model registry is a very simple module to hold all models:
module.exports = {
registerModel : function(model) {
if (! model.hasOwnProperty('modelName'))
throw Error('[model registry] models require a modelName property');
this[model.modelName] = model;
}
};
Because the model registry stores the model classes in this (which is module.exports), they can then be imported from other files where you need to access the model:
// mycontroller.js
var MyModel = require('model_registry').MyModel;
var instance = new MyModel(...);
Disclaimer: this worked for me, YMMV. Also, the code samples above don't take into account any asynchronous requirements or error handling, so the actual implementation in my case was a bit more elaborate.

Resources