13

I'm trying to modularize my node.js application (using express framework). The trouble I am having is when setting up my routes.

I am no longer able to extract the data I send to the post. (req.body is undefined). This works okay if it is all in the same file. What am I doing wrong here, and what is the best way to modularize code in node.js?

My app.js

require('./routes.js').setRoutes(app);

My route.js

exports.setRoutes = function(app){

  app.post('/ask', function(req, res, next){
    time = new Date();

    var newQuestion = {title: req.body.title, time: time.getTime(), vote:1};
    app.questions.push(newQuestion);
    res.render('index', {
      locals: {
        title: 'Questions',
        questions: app.questions
      }
    });
});
Kiran Ryali
  • 1,371
  • 3
  • 12
  • 18

5 Answers5

30

A better approach:

Create a routes.js file that contains:

var index = require('./controllers/index');

module.exports = function(app) {
  app.all('/', index.index);
}

Then, from within your server.js (or however you've started your server), you'd require it as such:

require('./routes')(app);

This way you aren't creating global variables that bring with them a whole slew of issues (testability, collision, etc.)

ctide
  • 5,217
  • 1
  • 29
  • 26
  • This is the better way to do this. I've started doing that in my projects already, thanks to you! – Kiran Ryali Jul 24 '11 at 04:20
  • This way works great, I found a more complete example at: http://stackoverflow.com/questions/6059246/how-to-include-route-handlers-in-multiple-files-in-express – JayCrossler Aug 13 '11 at 17:18
  • @ctide, how do you access app from index controller? – Mehdi Oct 07 '11 at 11:02
  • I don't, you shouldn't ever need to. What are you trying to accomplish within the route that needs the webserver object? The index function will receive req, res, and next arguments which should be all you need. – ctide Oct 08 '11 at 21:05
  • why app.all( ) instead of app.get( )? – qodeninja Oct 30 '12 at 21:01
  • no reason, the answer wasn't really about what the index controller action does – ctide Oct 31 '12 at 19:50
3

I realize someone already answered but here's what I do anyway.

app.js :

fs.readdir('./routes', function(err, files){
    files.forEach(function(fn) {
        if(!/\.js$/.test(fn)) return;
        require('./routes/' + fn)(app);
    });
});

./routes/index.js :

module.exports = function(app) {
        var data_dir = app.get('data-dir');

    app.get('/', function(req, res){
        res.render('index', {title: 'yay title'}
    });
}

Maybe someone will find this approach helpful.

OneOfOne
  • 95,033
  • 20
  • 184
  • 185
  • 1
    Take care that `require`is a synchronous function when `fs.readdir` is async. So each time the order of execution of your modules will be different when you run your app. But you can `sort` files array before `forEach` to make it determined. Also you can asyncly preload files to `require.cache` to make it more faster to start if your app need much restarts. – Alex Yaroshevich Nov 16 '13 at 01:44
2

My issue was that I was declaring app in the wrong way. Instead of var app = module.exports = express.createServer();, it should have just been app = express.createServer();

And then all I needed to do in my app.js was require('./routes.js');. Now the routes file has access to the app variable and now I can just declare routes normally in the routes file.

(routes.js)

app.get('/test', function(req, res){
    console.log("Testing getter");
    res.writeHead('200');
    res.end("Hello World");
}); 
Kiran Ryali
  • 1,371
  • 3
  • 12
  • 18
  • 4
    This is a bad practice because you're instantiating app as a global variable. You're better off passing it into the routes.js file (exporting an init function, for example, in the routes.js that accepts an app variable.) – ctide Jul 12 '11 at 19:09
  • It would be nice to know _why_ this 'bad practice' is the default setup provided by an express install :( Obviously globals are less than great, but this is the template us noobs are being provided. – Kato Dec 02 '11 at 07:08
0

example in app.js

var users = require('./lib/users'); //this is your own module
app.use(users);

then, you in your lib/users folder, create files ( index.js,user.ejs,etc). use index.js for default module load //index.js var express = require('express'); var app = module.exports = express();

app.set('views',__dirname);
app.set('view engine','ejs');
app.get('/users',function(req,res){
    //do stuffs here
});

I made an example of Modular node.jes + Boostrap here : Nodemonkey or a tutor here here

jsdev
  • 672
  • 6
  • 14
0

global "app" for me (usually). If you know the app wont be require()d, and if you're not clumsy it's a lot easier to work with

tjholowaychuk
  • 3,026
  • 1
  • 21
  • 6
  • Thanks for the answer! What kind of things should be avoided when using the global "app"? – Kiran Ryali Oct 08 '11 at 04:59
  • re-assigning it :D so if your app revolves around "applications" as a resource and you're likely to use "var app = " a lot I definitely wouldn't suggest it haha – tjholowaychuk Oct 08 '11 at 21:01