'How do I call one controllers method in another controller in Node

So I have one controller with a method defined as

controller1.js

 router.get('/:id/:field', function(req,res){
   var regex = /action|protocol|ip|port|direction|dip|dport|signature/;
     if (regex.test(req.params.field)){
       get(req,res,function(r){
         var field = req.params.field;
         res.status(200).send(r[field]);
       });
     } else {
         res.status(404).send("Signature Field Does Not Exist");
     }
 });

 function get(req, res, cb){
   MongoClient.connect(url, function(err, db) {
     if (err){
       console.error("Could not connect to database: %s",err);
       res.sendStatus(500);
     } else {
         var _id = req.params.id
         var collection = db.collection("signatures");
         var uniqueID = {"_id":_id};
         var cursor = collection.find(uniqueID); 
         cursor.hasNext(function (err, r) {
           if (err) {console.log(err);}
           else {
             cursor.next(function(err,r) {
               if (r == null){
                 res.status(404).send("Signature not found");
               } else {
                   cb(r);
                   db.close();
               }
             });    
           }    
         });
     }
   });
 }
module.exports = router

This works well in its own class and I can call it from outside via localhost. I want to be able to use both of these in another controller. So in another file

controller2.js

var controller1 = require("./controller1.js");
router.get('/', function(req,res){
  controller1.get(req,res,cb(r){
      res.status(200).send(r);
  });
});

When I attempt to call get in controller2.js I get Error: Route.get() requires callback functions but got a [object Object]. I am sure it is not a database error or connection error of any sort just an error in calling controller1 function from controller2. I've tried changing the header in controller1 to be

router.get = function(req,res,cb){
    ....
});

This makes the get in controller1 unable to call the function.



Solution 1:[1]

If you still want to follow this approach, the solution is:

router.get('/:id/:field', function(req,res){
   var regex = /action|protocol|ip|port|direction|dip|dport|signature/;
     if (regex.test(req.params.field)){
       get(req,res,function(r){
         var field = req.params.field;
         res.status(200).send(r[field]);
       });
     } else {
         res.status(404).send("Signature Field Does Not Exist");
     }
 });

 var get=function(req, res, cb){
   MongoClient.connect(url, function(err, db) {
     if (err){
       console.error("Could not connect to database: %s",err);
       res.sendStatus(500);
     } else {
         var _id = req.params.id
         var collection = db.collection("signatures");
         var uniqueID = {"_id":_id};
         var cursor = collection.find(uniqueID); 
         cursor.hasNext(function (err, r) {
           if (err) {console.log(err);}
           else {
             cursor.next(function(err,r) {
               if (r == null){
                 res.status(404).send("Signature not found");
               } else {
                   cb(r);
                   db.close();
               }
             });    
           }    
         });
     }
   });
 }
module.exports.router = router
module.exports.get = get


In controller2
var controller1 = require("./controller1.js");
router.get('/', function(req,res){
  controller1.get(req,res,cb(r){
      res.status(200).send(r);
  });
});
will work

Just do some changes accordingly. Wherever you require controller1 from router object just convert that to:

require('./cotroller1').router

Solution 2:[2]

To keep your code DRY you can keep all your repeating functions into helper modules.

The structure can be something like this:

controllers  
??? helpers  
    ??? index.js  
??? controller1.js   
??? controller2.js  

In the "index.js" helper module you can include your function like this:

exports.yourFunction = function(args){
...
};

And you can call it in the controllers like this:

var helpers = require("./helpers");
...
helpers.yourFunction();

Also, you can find other related answers in this thread:

Javascript - Best way to structure helpers functions in NodeJS

Solution 3:[3]

var test = require("./test");
...
test.myFun();

Solution 4:[4]

It's a code smell/bad design decision/anti-pattern to call functions from one controller contained in other controller.

My suggestions is that if you need to reuse/share common functions to two or more modules consume it, create a third module that you can share to your controllers.

Speaking in good organization/best practices for web applications, create a layer of "service" files that will talk to databases, and all kinds of infrastructure/external services. Then in your controllers, just import and call that functions from these service modules, letting controllers more focused on what they are meant to be: receiving and responding to requests.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Community
Solution 3 Gtm
Solution 4 Jone Polvora