How to access app.locals in other modules in NodeJS? - node.js

With my main server.js file, I exported my app variable:
//Assume there's other code in this file of course
var app = express();
app.locals.database = //here's my DB connection. This variable works perfectly within the server.js file!
module.exports = app;
I imported it into another module:
var app = require('../server');
But I cannot access the app.locals variables? I set a few of them within my server.js (such as database connection info) but I get this error:
TypeError: Cannot read property 'database' of undefined
when trying to read:
app.locals.database
What am I doing wrong?
NOTE: In my other module app is {}, but when I check it within the originating module it has tons of info.

As per docs Once set, the value of app.locals properties persist throughout the life of the application.
In your case, as you've exported app, it's perfectly fine to access this at file level (not sure the right term), where you've imported as app.locals.database (remember app is an object).
But if you want to access elsewhere where you've not imported, express makes it available to all middleware via req.app.locals. The docs clearly mentions Local variables are available in middleware via req.app.locals
Also checkout this SO question, it give you a nice insight on app.locals and req.locals

Related

NODE JS APP: What does this notation mean?

I've picked up a project from another developer, uses the typical MEAN stack with the entry point being server.js.
Now, in server.js, the module that does:
var express = require('express');
var app = express();
var passport = require('passport');
There are another 2 lines of code that look like they are doing some sort of routing but I can't figure out what it actually means:
require('./routes.js')(app, passport);
require('./apiRequest/authenticate')(app, passport);
I'm confused because it looks like require() is called from the global scope, whereas all the other routing methods are called off app, i.e app.use(). Can someone explain what the sets of parameters mean, and why are there two sets also where is require() called from, is it provided by Express?
routes.js and apiRequest/authenticate are two local (project) modules / js files that are basically required here.
express and passport are node modules/libraries that are provided from npm_modules, via node module resolution.
app is simply an express instance created by invoking the express module/default function.
The parameters passed to the required local modules (routes and authenticate) are just parameters passed to those modules (default exported function) that can be used further in those files (e.g. if you look in routes.js you will probably see that they use app.use(..., where app is given as param as well as the passport module)
To explain the syntax require('./routes.js')(app, passport); more clearly:
require - node OOB function for importing modules into the current file/module
require('./routes.js') resolves the default export from the routes.js file which in this case is a function
...(app, passport) this function (from above point) is then invoked with the provided params (which were previously defined here - i.e. imported with require)

Scoping issue using require() in node JS

I set up a web server using node JS and the Express module. My code is as follows :
file tree:
/src
|
+-- server.js
+-- /app
|
+-- routes.js
server.js
// set up ======================================================================
var express = require('express');
var app = express();
var mongoose = require('mongoose');
...
// configuration ===============================================================
mongoose.connect(configDB.url);
...
// routes ======================================================================
require('./app/routes.js')(app, passport);
// launch ======================================================================
app.listen(port);
routes.js
module.exports = function(app, passport) {
app.get('/some-route', function(req, res) {
// this line bugs out
var User = mongoose.model('User', userSchema);
});
};
My question:
Calling mongoose.model() in routes.js throws the following error
ReferenceError:mongoose is not defined
Why is mongoose not known in this context when I've included it in server.js, the file in which routes.js is being included? Should I require() mongoose again in routes.js? What am I missing here?
Variables defined within a module are local only to that module. They are not in the scope of other modules that you require() in with that module. That's why mongoose is not know to your routes module. The require() operation does not insert the code right into the calling module. Instead, it loads that code from disk and then inserts it into its own function and calls that function. This gives each loaded module its own independent scope. It is not inserted into the current scope.
In cases like this, you have several choices:
Require() in the mongoose module again in routes. This is generally preferred when possible because this makes the routes module more self sufficient and easier to reuse as it requires in the things it needs.
Pass in the object you want to share with the routes constructor just like you are passing in app and passport. This method is preferred when the item needed by the other module is not just the result of a simple module load. For example, app is the result of calling a constructor function so the only way for another module to use the same app instance is for you to pass it.
You can have routes call out to some other module to request information. For example, since you've already passed the app object to routes, you could put the mongoose object as either a property on the app object so it could be referenced that way or you could add a method to the app object to retrieve it via the method call.
In this case, since mongoose is just a cached module, it probably makes the most sense to just require() it in again, but any one of the three methods above would work.
The modules that are included is on a file are not visible on another file. Here you can find a list of the global objects that are available on every module that you create:
https://nodejs.org/api/globals.html
All the other objects/variables that you define within a file they are defined within the context of this file. Otherwise, this could create huge problems with variables that overwrite other variables in other files and creating a mess within a project. You can think of a file like a function that includes all your code and everything that is defined in there, is not available to the global namespace.
In your case, you have to require('mongoose') in the files that you need it, and it is built like that so that can maintain the existing connection to the database.

How can I access an environment var in other modules

I use the jsonwebtoken module to Encode and Decode JWTs.
The Secret-passphrase is being saved in a config.yml file, which is being loaded in my main index.js Javascript and stored into an app Environment var app.set('jwtToken', config.jwt.token).
How can I access this environment var in another module (for example the Auth-Route Module).
Can I pass it somehow to this file?
Many thanks
I think you will need access to your app instance to access the jwtToken var in app. Alternative for you would be to pass your jwtToken as an process environment variable via
JWT_TOKEN=xyz node server.js
Now you could access it via process.env.JWT_TOKEN

After Express App is initialized, I can't add objects to module.exports

server.js
module.exports.a = 'abc';
var app = expressAppConstructor(db);
module.exports.b = 'xyz';
console.log(JSON.stringify(module.exports)); // --> {"a":"abc","b":"xyz"}
exportsLog.js
var io = require('./server');
console.log(JSON.stringify(io)); // --> {"a":"abc"} Note b: xyz is missing
How can I add b to module.exports after the Express App is initialized?
I'm on the mean.js Stack and the mentioned files above are server.js, expressConstructorFunction is require(./config/express.js)
See original contents of server.js, config/express.js
After debugging with your actual app I've discovered the reason the second setting doesn't work. It does work, but when you initialize your express app you are requiring the server file in one of your routes.
node server.js -> exports.a = 'abc'; -> expressAppConstructor ->
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
-> in one route file loaded via the above, this runs: require('server.js'); -> now finally the stack returns to the server file and does: exports.b='xyz';, but the module has already been required and cached by your route file.
I would actually be worried that you're starting the server over and over each time you require the file. Though I think it's not breaking because node caches modules that have been required so the logic isn't running, but the exports on the cached server module only has the first assignment since it was required by your route file before the second assignment to exports even occurs. By the time your route file tries to load the server file, it has only run up to the app initialization line. Anything added to exports after you've required it in your route file obviously isn't going to make it onto the exported data.

Best place to define a connection uri using Express

I have just started learning ExpressJs and I am trying to use it with mongoskin.
What I want to know is where is the best place to define the uri to connect to the database. I don't want to do that in every file that needs to connect to the db.
I tried doing this in my app.js file:
var app = express();
...
app.set('db_uri', process.env.NODE_DB || ""localhost/test"");
...
module.exports = app;
And inside the file that would be accessing the db:
var mongo = require('mongoskin'),
app = require('./../../app'),
db = mongo.db(app.settings.db_uri);
But the problem is that I always receive an empty object for app.
So, I have two questions.
1) Is this the best way to do it?
2) What is wrong that I can't access app?
I think one way of doing it is creating a module that handles the interaction with the database, so you could:
write the url there
or in a configuration file required in it
or you could just use process.env
and require the model when you need database interaction, this way there's no need for express to know about it.
About app not being required: check that you are exporting it via module.exports and that the path is correct (the first ./ could be omitted for example).

Resources