Reputation: 178
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
Reputation: 5291
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...)
routes
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