Binding Routes to a main file - node.js

I am building an application using nodeJS and angularJS. I have different routes belonging to different groups. Is there a way I can mention routes belonging to different groups in seperate files and import them into main server js file and use the methods directly from the main server js file?
Can someone help me with this?

I am binding my subroutes file using require('./ subroutes.js') in the main server js file. And in the subroutes.js, I am encapuslating my routes in module.exports = function(app){
//write your routes here
}
Another important thing here is that if your subroutes needs any variables set from server.js file, then you need to include 'server.js' in subroutes.js file as below
var file = require('./server.js');
module.exports = function(app){
//write your routes
//If you need to use variables from server.js, use file.variablename wherever needed.
}
This works!

Related

Node.js express: access application config from required modules

I've got a large Node.js Express API to build, so I want to make sure my solution architecture is stable and scalable.
The routes are defined each in its own separate file and stored in /routes folder. There's an index.js file as well, where all of the child routes are registered to the master router.
There's an application configuration file /config/app.js:
module.exports = {
development: {
configVar: 123
},
test: {
configVar: 456
},
production: {
configVar: 789
},
}
The config object is loaded in the main application index.js file:
const path = require("path");
const env = process.env.NODE_ENV || "development";
const config = require(path.join(__dirname, 'config', 'app.js'))[env];
Now that I have the config object, I'd like to pass it down to whatever consumer. For Express app it's mostly the routes. Loading the config repeatedly in each module would be kind of redundant. So I have set up my main routes module (/routes/index.js) as follows:
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.use('/test', require('./test').init(config));
return router;
}
}
And the /test route (/routes/test.js):
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.post("/", function(req, res) {
res.send('hello world');
});
return router;
}
}
I also like that with this structure I can mock the config object when testing the routes. My question is, if this can be considered a good pattern for Express application, or perhaps there is some convention to follow.
There are many ways to skin a cat and many more ways to setup an express project.
The one thing that jumps out at me as a good thing to change is your configuration method. Your approach makes total sense, but there's a module called config which works in much the same way you've illustrated but you won't need to list every option for every environment.
Using this module you can have a default.json file which contains all of your base configurations. You can then override it with a file which matches the name of your environment such as development or test without having to do it by hand.
More importantly, it will also let you map from your applications configurations to Environment Variables. You very rarely want to store your applications configuration values in the codebase itself, especially when we're talking API keys and secrets. The last thing you want to do is commit API keys / secrets into version control. The config module linked above will allow you to define environment variable mappings which means you can feed them in via the systems environment variables instead.
I should note finally that there are many modules which act in a similar way to config and they all function slightly differently. You might also want to consider nconf which is also a brilliant module.

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.

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).

accessing required modules from other modules

I have a bare-bone express application, exactly the one that is created with the express command.
I have installed socket.io and attached it to my server, like this:
var app = express(),
server = http.createServer(app),
io = io.listen(server);
server.listen(8000);
Now, I also have the routes files, which is called like this:
app.get('/', routes.index);
Inside this module I have the following function:
exports.index = function(req, res){
socket.emit('news', { message: "foo" });
};
This obviously leads to a 500 reference error, because the routes file is an exportable module, and obviously has no idea what the socket is, as it is located in the app.js file.
Is there a way I can access this socket object from this, or any other file? Please note that it is attached to the express generated app. Here is a link to said project: http://jsfiddle.net/E27yN
extra: what about getting/setting session data?
Thanks in advance.
If I'm reading this correctly, I had a very similar problem: Handling Node.js Async Returns with "require" (Node ORM)
The way I resolved it was by putting a function call to the require, and returning that function in my exports, then that was accessible via that local variable. In your case, I think it'd be something like this:
var routes = require("routes.js")(io);
console.log(routes.index()); // will log return of the function "index" in routes.js.
// in routes.js
module.exports = function(io) {
var exports = this;
exports.index = function(req,res,io) {
// now io.socket is available to routes
console.log(io);
}
return exports;
}
Now you can access whatever you've exported by using that variable. So getting and setting session data would be a matter of getting that info to/from the proper place and modifying it in your parent file (usually whatever you're launching with node, like app.js or what have you).
Hope this helps!
EDIT: After discussing this in the comments, I think the problem is you're trying to use express and socket.io on the same port.
The example they give in your link (http://socket.io/#how-to-use) actually shows that they are serving up index.html from app.get("/"). Index.html includes the socket.io script file () which is by default served up when you start your socket server.
That would look like this jsfiddle: http://jsfiddle.net/Lytpx/
Note that you serve up the index.html page through express, but your socket service actually serves up /socket.io.js which then makes connection calls to the listening socket service (note, you may want to change localhost in your io.connect call in index.html to whatever your server is).

Resources