r/node•
jbeardles

Help -- Custom Middleware and Revealing Module Pattern

I'm trying to create a small piece of custom middleware to connect to a mongodb instance using the revealing module pattern. However, I'm having trouble when passing it to app.use. I'm getting an error stating there is no method 'connect'. Code below -- any help would be greatly appreciated!

var DB = (function() {
    // Private methods
    function _db() {
        mongoose.connect('CONNECTION STRING', function(err) {
            if(err) { console.log("Error: " + err) }
            else { console.log('Connected to mongo db') }
        });
    }

    // Public methods
    function connect() {
        _db();
    }

    return {
        connect: connect
    }
})();

module.exports = function() {
    return DB;
};

Posted Oct 25, 2014, 11:58 PM UTC

34
burtbeckwith•

This is what I would do:

module.exports = function() {

    // Private methods
    function _db() {
        mongoose.connect('CONNECTION STRING', function(err) {
            if(err) { console.log("Error: " + err) }
            else { console.log('Connected to mongo db') }
        });
    }

    // Public methods
    function connect() {
        _db();
    }

    return {
        connect: connect
    }
};

There's no need for the auto-invoking function because the hash that you return defines what's public and private.

1
jbeardlesOP•

That actually makes a lot of sense. I'm able to see my object getting exported correctly and the connect method is exposed correctly. However, now I'm getting 'TypeError: app.use() requires middleware functions'.

My Google-fu is proving to be pretty weak on this one, but I'll keep on trucking. Thanks for pointing me in the right direction :)

1
NeoMarlin•

Check the documentation for app.use. There's nothing magical about writing middleware, it's just a function taking a request and modifying a response, just like a route.

So to comment on your middleware:

  1. You have to return a response (if your middleware is terminal, which it isn't) or call the next piece of middleware (remember routes are just middleware like everything else).
  2. You don't respect the function signature for a middleware.
  3. You do something async, which you probably expect to finish before the next middleware is called, without waiting for it to finish.

Fixing these:

//The signature outlined in the docs
module.exports = function(req, res, next) {
       mongoose.connect('CONNECTION STRING', function(err) {
           if(err) {
              //We could not connect so we will pass on the error and let
              //error middleware handle this
              return next(err);
           }
           //We could connect so we will assign the connection to a local
           //so other middleware can use it and call the next middleware
           res.locals.connection = mongoose.connection;
           return next();
       });
};

Now, I'm not too familiar with mongoose, so I don't know if it will reuse an open connection and just call the callback immediately, or try to connect on every single request. But that begs another question; why are you wrapping this in a middleware? Normally, if your application depends on this connection, you wouldn't allow the server to start, without having connected first.

1
jbeardlesOP•

Thanks, this is exactly what I needed (and exactly what I, somewhat inadvertently, ended up coming up with on my own). Turns out I was confusing the nature of middleware and not understanding that it was something that would be run on every request (hopefully I have that right, still pretty new to node in general).

I ended up doing what you said and and not wrapping it in middleware and just having the server make the connection directly.

1