0

I want to make sure every time an express.js app starts, there is a query made to the mongodb instance user collection to insure that the superadmin account exists. However, everything in the setup phase of an express.js app is synchronous.

Some ideas I have are:

  1. Have a system that registers modules. Each module can be loaded with require and has an init method which can be called using the async module's each method which is passed a callback. Once all the init methods on the module have finished executing the callback function will then run app.listen(process.env.PORT).

  2. Write an installation script that is outside the express.js app that is executed at the command line. This script connects to the mongodb database with mongoose, makes a few queries, and terminates. It can be added to the heroku.sh file to insure that it run every time the express.js app is started.

  3. Use waitfor to run the database queries synchronously during the express.js setup phase? This will keep the idea and code clean and simple but it seems like overkill using Fibers for just this one task.

Adam S
  • 509
  • 10
  • 24
  • 1
    Why wouldn't you just check for existence of your superadmin user prior to setting up/launching express? – Wake Aug 16 '16 at 20:42
  • Because it requires making an asynchronous call using mongoose. Should I use the waitfor node module to run that code synchronously when express is starting? – Adam S Aug 16 '16 at 20:49

2 Answers2

3

You don't need to perform the database lookup synchronously. Just start your express server in the callback from your database request once you've verified that the user exists. Here's a pseudo-example:

mongoclient.open(function (err, mongoclient) {
    if (err) throw err;  // or otherwise handle it

    var db = client.db("dbname");
    var findAdminUserJSON = {
        // whatever your lookup criteria
    };
    db.collection("user").findOne(findAdminUserJSON, function(err, adminUserData){
        if (err) throw err;  // or otherwise handle it

        if(adminUserData){
            // start express server
        } else {
            // however you want to handle the case of no admin user
        }
    });
});
Wake
  • 1,686
  • 10
  • 14
0

I just isolated an init function into a separate file. It only checks the database for the admin user here but in the future, I can register modules which are passed the app and db objects and I'll use async.each to asynchronously load modules and run the init method on each to start off the system. Once that they are all registered run init on the express server.

server.js:

'use strict';
// Set the 'NODE_ENV' variable
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
process.env.PORT = process.env.PORT || 3000;

// Apparently __dirname doesn't work on Heroku
// @link http://stackoverflow.com/questions/17212624/deploy-nodejs-on-heroku-fails-serving-static-files-located-in-subfolders
process.env.PWD = process.cwd();

// Load the module dependencies
var mongoose = require('./server/config/mongoose'),
    express = require('./server/config/express'),
    init = require('./server/config/init');

// Create a new Mongoose connection instance
var db = mongoose();

// Create a new Express application instance
var app = express(db);

// Run the init this way in future refactor modules into separate folders.
init(app, db)
    .then(function initialized() {

        // Use the Express application instance to listen to the '3000' port
        app.listen(process.env.PORT);

        // Log the server status to the console
        console.log('Server running at http://localhost:' + process.env.PORT + '/');
    });

// Use the module.exports property to expose our Express application instance for external ussage
module.exports = app;

server/config/init.js:

'use strict';

var config = require('./config');

module.exports = function(app, db) {
    return new Promise(function(resolve) {
        var User = db.model('User');
        User.findOne({ email: config.adminAccountEmail}, function(err, user) {
            if (err) throw err;
            if (!user) {
                var newAdmin = new User({
                    email: config.adminAccountEmail,
                    password: config.adminAccountPassword,
                    roles: ['administrator', 'authenticated', 'anonymous']
                });
                newAdmin.save(function(err) {
                    if (err) throw err;
                    resolve();
                })
            } else {
                resolve();
            }
        })
    })
};

server/config/production.js:

'use strict';

/**
 * Set the 'production' environment configuration object
 * @link http://docs.mongolab.com/migrating/
 */

module.exports = {
    db: process.env.MONGODB_URI,
    // set this to build
    // dir: 'build/',
    dir: 'client/',
    fileDir: 'files/',
    sessionSecret: process.env.SESSION_SECRET || 'MEAN',
    adminAccountEmail: process.env.ADMIN_ACCOUNT_EMAIL || 'admin@simpleyachtjobs.com',
    adminAccountPassword: process.env.ADMIN_ACCOUNT_PASSWORD || 'password'
}
Adam S
  • 509
  • 10
  • 24