Issue importing the connect-roles object with require

I am building an app with nodejs and expressjs. For authentication and user roles I am using respectively passport and connect-roles.

I have built the connect-roles object as shown in here: https://github.com/ForbesLindesay/connect-roles

Like so:

var user = new ConnectRoles()

This is in my app.js. Then I have exported such object like so:

exports.user = user;

However, if I import this object with require I see a strange behavior, please check code below:

var express = require('express');
var router = express.Router();
var user = require('../app.js');

//1
console.log(user);

/* GET users listing. */
router.get('/', function(req, res) {
  //2
  console.log(user);
  res.send('respond with a resource');
});

module.exports = router;

The object is undefined in case 1 and is as it should be in case 2. Basically, I get 2 different objects depending if I am inside or outside the router.get function. I have been debugging this for half day, but I can't figure out what is happening.

The issue is that this object should be injected to provide roles management like so:

router.get('/', user.is("admin"), function(req, res) {

Of course this gives an error since user outside the get function object is undefined. The error is "cannot call method is of undefined".

I can't see how user would be undefined there... but I can suggest that you use

module.exports = user

As this will give you the object:

{ functionList: [],
  failureHandler: [Function: defaultFailureHandler],
  async: false,
  userProperty: 'user' }

Rather than:

{ user: 
   { functionList: [],
     failureHandler: [Function: defaultFailureHandler],
     async: false,
     userProperty: 'user' } }

With your current implementation you could do:

router.get('/', user.user.is("admin"), function(req, res) {

If this does not solve your issue you may need to provide app.js in it's entirety.

The problem you have is most likely a cyclic dependency. Your router file requires your app.js file and your app.js file requires your router. What this means is that your router file gets a partially initialised object, that is only later filled in. The best way around this is to factor out the roles into a separate module, then require it from both places. i.e. have an authorisation.js file that looks like:

var ConnectRoles = require('connect-roles');
var user = new ConnectRoles();

// set up all the authorisation rules here

module.exports = user;

Then in both app.js and the router file, do var user = require('./authorisation.js');

This is a general problem whenever you create cyclic dependencies, and is not specific to connect-roles.