0

Introduction

So far I have three files, one test.js is a file where I have built three functions that work.

But now I am trying to structure using MVC or at least some pattern. So now I router.js and app.js

Question

Should I put my promise functions from test.js in my config.js or server.js or something else, Im just interested in how people would do this and whats the correct way of structuring NodeJS.

  1. server.js

In here start the server and apply the routes to my app

var configure = require('./router');
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;

// get an instance of router
var router = express.Router();
configure(router);

app.listen(port);
console.log('Server has started!! ' + port);

// apply the routes to our application
app.use('/', router);
  1. config.js

In here I build my routes

module.exports = function (router) {

    // route middleware that will happen on every request
    router.use(function (req, res, next) {

        // log each request to the console
        console.log(req.method, req.url);

        // continue doing what we were doing and go to the route
        next();
    });

// home page route (http://localhost:8080)
    router.get('/', function (req, res) {
        res.send('im the home page!');
    });

// sample route with a route the way we're used to seeing it
    router.get('/sample', function (req, res) {
        res.send('this is a sample!');
    });


// about page route (http://localhost:8080/about)
    router.get('/about', function (req, res) {
        res.send('im the about page!');
    });

// route middleware to validate :name
    router.param('name', function (req, res, next, name) {
        // do validation on name here
        console.log('doing name validations on ' + name);

        // once validation is done save the new item in the req
        req.name = name;
        // go to the next thing
        next();
    });

// route with parameters (http://localhost:8080/hello/:name)
    router.get('/hello/:name', function (req, res) {
        res.send('hello ' + req.params.name + '!');
    })

    // app.route('/login')

    // show the form (GET http://localhost:8080/login)
        .get('/login', function (req, res) {
            res.send('this is the login form');
        })

        // process the form (POST http://localhost:8080/login)
        .post('/login', function (req, res) {
            console.log('processing'); // shows on console when post is made
            res.send('processing the login form!'); // output on postman
        });
};
  1. test.js

In here is a list of functions that are a chain of promises getting data and API Keys

(small function, one of many that feed into each over)

var firstFunction = function () {
    return new Promise (function (resolve) {
        setTimeout(function () {
            app.post('/back-end/test', function (req, res) {
                console.log(req.body);
                var login = req.body.LoginEmail;
                res.send(login);
                resolve({
                    data_login_email: login
                });
            });
            console.error("First done");
        }, 2000);
    });
};
4
  • 1
    Actually your config.js is not configs at all but routes. So call them routes.js and import express.Router directly to router.js instead of passing it.
    – jstice4all
    Commented Jun 19, 2017 at 14:33
  • Plus 1 for the knowledge thanks
    – Beep
    Commented Jun 19, 2017 at 14:38
  • And better use this approach from official documentation expressjs.com/en/guide/routing.html#express-router
    – jstice4all
    Commented Jun 19, 2017 at 14:39
  • Thanks @jstice4all looking into it now
    – Beep
    Commented Jun 19, 2017 at 14:40

1 Answer 1

2

My recommended structure is to put everything except server.js in lib directory so all your app is lib/ plus server.js - everything else is package.json, dependencies in node_modules (created on npm install, not in the repo), .gitignore, config files for Travis, Circle, Heroku or whatever service you're using, some README.md and things like that.

Now, server.js is just bare minimum that requires lib/app:

const app = require('./lib/app');

and starts the server with something like:

const server = app.listen(app.get('port'), () => {
  logger.info('%s listening on port %s', app.get('name'), app.get('port'));
});
server.on('error', (err) => {
  logger.error(err.message || err);
  process.exit(1);
});

where logger is some higher lever logger like Winston or something like that.

That's it. Now, lib/app.js is minimum code that loads the middleware like body parsers etc., creates the express app and sets the variables for port and name and then uses a router that is exported by lib/routes:

const routes = require('./routes');
// ...
app.use('/', routes);

The lib/app should be enough to use for testing with tools like supertest but it doesn't listen on any port - server.js does. This is important to simplify testing.

The router exported by lib/routes is used for everything and you can start with a single lib/routes.js file and then convert it to lib/routes/index.js plus several files in lib/routes as needed.

The routes only define the actual routes and input validation with a module like e.g. express-validation and register controllers that are exported by lib/controllers - that can start as lib/controllers.js and get converted to lib/controllers/index.js plus lib/controllers/*.js as needed - just like the routes.

Then I would add top level spec or test or tests directory where all of the tests go. The tests can require your lib/app to run the tests on it with no need to listen on actual TCP ports - those will test your routes with actual controllers. Other tests will require lib/util and run some unit tests on your utilities etc. Make sure to use a tool like istanbul or nyc to calculate the test coverage.

The database schemas and data models would go to lib/schemas and lib/models, some utility helpers in lib/util, some config loading code in lib/config etc.

This is quite flexible layout and works pretty well. You can start with just few files:

README.md
LICENSE.md
package.json
server.js
lib/app.js
lib/routes.js
lib/controllers.js
lib/config.js

etc. and easily convert all of the xxx.js file into xxx/index.js with entire folder of smaller xxx/*.js files as needed.

The main difference from your approach is that I recommend exporting routers and using them by higher level routers instead of passing the high level router into lower lever modules that export functions that take routers to work on.

So instead of:

const moreSpecific = require('more-specific');
const moreGeneral = express.Router();
moreSpecific(moreGeneral);

and then in more specific:

module exports = (router) => {
  router.use('/abc/xyz', ...);
};

I would recommend exporting a more specific router in a file e.g. routes/abc.js:

const router = express.Router();
router.use('/xyz', ...);
module exports = router;

and then in more general router e.g. in routes/index.js:

const abc = require('abc');
const router = express.Router();
router.use('/abc', abc);
// and export the main router for other modules like app.js to use:
module.exports = router;

to have a route like /abc/xyz.

1
  • Nice answer ! , Right im going to read through this and once I have get back to you. thank you, im still trying to alter my app to work with this structure once i get this working ill accept. I can see how this is much more expandable and has room to grow +1
    – Beep
    Commented Jun 19, 2017 at 16:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.