Getting error CreateListFromArrayLike called on non-object when trying to use .apply()

I've created a simple little route parsing function so that I can keep my code clean and easily maintainable, this is the little function that gets ran when the app starts up and parses the config.json file and binds the appropriate methods and request paths:

const fs = require('fs');
const path = require('path');
module.exports = function(app, root) {
  fs.readdirSync(root).forEach((file) => {
    let dir = path.resolve(root, file);
    let stats = fs.lstatSync(dir);
    if (stats.isDirectory()) {
      let conf = require(dir + '/config.json');
      conf.name = file;
      conf.directory = dir;
      if (conf.routes) route(app, conf);
    }
  })
}

function route(app, conf) {
  let mod = require(conf.directory);

  for (let key in conf.routes) {
    let prop = conf.routes[key];
    let method = key.split(' ')[0];
    let path = key.split(' ')[1];

    let fn = mod[prop];
    if (!fn) throw new Error(conf.name + ': exports.' + prop + ' is not defined');
    if (Array.isArray(fn)) {
      app[method.toLowerCase()].apply(this, path, fn);
    } else {
      app[method.toLowerCase()](path, fn);
    }
  }
}

The problem I have is some times I need to pass in multiple arguments to an express router, e.g. in the case of using passport something like this:

exports.authSteam = [
  passport.authenticate('facebook', { failureRedirect: '/' }),
  function(req, res) {
    res.redirect("/");
  }
];

So I figure I can just pass them as an array, and then parse them into the router appropriately, my config for example looks like this:

{
  "name": "Routes for the authentication",
  "description": "Handles the authentication",
  "routes": {
    "GET /auth/facebook": "authFacebook",
    "GET /auth/facebook/return": "authFacebookReturn"
  }
}

The only problem is I'm getting this error:

     app[method.toLowerCase()].apply(this, path, fn);
                                ^

TypeError: CreateListFromArrayLike called on non-object

if I console.log(fn) I see [ [Function: authenticate], [Function] ]

I'm not exactly sure what I am doing wrong, any information would be great thanks.


Solution 1:

You need to send the params as an array, like this:

app[method.toLowerCase()].apply(this, [path, fn]);

If you want to send an arguments list you need to use call:

app[method.toLowerCase()].call(this, path, fn);

Source: call, apply

Solution 2:

Fixed it by changing:

eval.apply(this, 'p1', 'p2')

to:

eval.apply(this, ['p1', 'p2'])