Obzzen
Obzzen

Reputation: 178

Passing arguments from middleware to express router

This question is haunting me since long time and i've never found a answer that explained to me this clearly.

I'm using Express 4.0 and i've made this snippet to show you the solution that i've made, to get the result that i've needed.

I want to pass the argument req.method and one array of routes controllers.routes directly into the express router to define the method and to filter routes as it comes in the middleware.

var controller = require( './controllers' );

module.exports = function ( app ){

    app.router.use(function ( req, res, next ){

        // function with the args before router get called
        anotherFn( app, req.method, controller );

        // Call the express router after called function with args
        next( 'route' );

    });

};

function anotherFn( app, method, controller ){

    // Express router called with args here...
    app.router[ method ]( controllers.routes,
        function ( req, res, next ){

            try{
                controller[ req.config.action ]( req, res, next );
            }catch( e ){
                next( 'error' );
            }

        }
    );

};

Its working at the moment, but it seems to me a little hacky or sketchy cause i think that the function never get resolved or the middleware calls for the route after calling the anotherFn function and its strange how is it working and doesn't seem a good practice.

I'm afraid that in the future this could give me problems with asynchronism or could be hard to maintain cause doesn't seem solid code ( or at least for me ).

Now my question is, if this is a good practice and i can keep this as it is or if there is another way to pass this arguments to the router that doesn't seem so hacky and strange.

Upvotes: 2

Views: 3092

Answers (1)

cusspvz
cusspvz

Reputation: 5291

tl;dr

You must keep in mind that you must have 2 stages on an MVC based node server: Configuring stage and Working stage; which are the construction base for the 7 abstraction processing layers: Network Server (http/https/spddy/...), Request/Response Middleware system (express/connect), Router and Routes (Express Router, Simple router, emvici router), Controller, Model (mongo-cli/sequelize/...) and finally View (jade/ect/mustache/...)

All abstraction layers should be initialized and configured before going into a working stage. If your server is already receiving requests and perhaps Views aren't working yet, they will be producing errors. You're configuring Router/Routes inside the Router working state.


Seems that are some miss understanding concepts over there. Middlewares are used to be executed per each request. Controllers (supposing MVC here) are meant to save actions per each kind of data. Usually with an MVC pattern you always have a Router/Routes, some frameworks do that under the hood, others give you access to do so.

Happens that Express and mostly most well known nodejs modules are great for not following entirely the concept of a framework, they provide features around their goals but they provide only basic API stuff to let you glue with others. Thats the reason why you found various tutorials on google for the same propose but with completely different implementations.

Now, back on track to your doubt, the binding between Controllers and the Router should be done by creating Routes. The way you're doing, you're adding routes into express every time someone does a request, and thats a memory intensive/bad approach.

I advise you to think in an abstraction layer before you start coding on that. Lets suppose you need Controllers, Models, Views, one Router, one Http Server (not app yet) and a app (usually app is a middleware connection part, could be connect, express and so on...)

  • server.js - here you could abstract about you service, thats the place to choose if it would be an http/https/spdy and so on...
  • app.js - App should grab all requests from the server, pass them trough a group of middlewares you need and last but not least, router as a middleware
  • router.js - When requests hit router, they should be already with all the data you need, now its time to redirect them to a route. For that to happen, router should have their routes configured and ready. Here you should require routes
  • routes/
    • index.js - here you can export all routes you have on this folder, or if you prefer, configure them here. Each route can require the needed controller.
  • controllers/ - you may not need an index since each route is requiring each controller. On each controller you could require needed Model and View.
  • models/ - you may not need an index since each controller that needs a model is requiring them.
  • views/ - views are meant to be required by the controller, but on express case, they have a View Engine that does that. Take a look on their docs for further details

Now something more codeific to your case:

server.js

var http = require( 'http' )
var server = http.createServer()
module.exports = server

app.js

var server = require( './server' )
var app = require( 'express' )()
module.exports = app

// Grab middlewares here...
// ...

// Now configuring router
app.use( require( './router' ) )

app.listen( server );

router.js

var router = new require( 'express' ).Router()
module.exports = router

// Load routes
require('./routes' ).forEach(function ( route ) {
  route( router )
})

routes/index.js

exports.user_example = require( './user_example' )

user_example.js

var UserController = require( '../controller/user' )

module.exports = function ( router ) {
  router
    .route( '/user' )
    .post(UserController.create)
    .put(UserController.create)
  ;
  router
    .route( '/user/:id' )
    .get(UserController.view)
    .post(UserController.update)
    .put(UserController.update)
  ;
  router
    .route( '/user/delete/:id' )
    .get(UserController.delete)
  ;

}

controller/user.js

// Here you should bind your modules

exports.create = function ( req, res, next ) {
  res.send( 200, 'created' )
}

exports.view = function ( req, res, next ) {
  res.send( 200, req.param( 'id' ) )
}

exports.update = function ( req, res, next ) {
  res.send( 200, req.param( 'id' ) )
}

exports.delete = function ( req, res, next ) {
  res.send( 200, req.param( 'id' ) )
}

Hope it helped! José Moreira

Upvotes: 7

Related Questions