javascript - How to make dynamic chain of middleware in express.js -
i working on project develop api manager control existing api.
it contains list of "before" , "after" middlewares, used things security checking , logging. , "service" middleware http request existing api. problem want make order middleware being executed dynamic, meaning load configuration file change order middleaware executed every time request comes in.
here previous code:
'use strict'; // loading express library var express = require('express'); var app = express(); var service = require('./routes/index'); // testing configurable middleware var confirguration = { before1: { priority: 100, enable: true }, before2: { priority: 80, enable: true }, service: { priority: 50, enable: true }, after1: { priority: 30, enable: true }, after2: { priority: 10, enable: true } } var before1 = require('./example_middleware/before1'); var before2 = require('./example_middleware/before2'); var after1 = require('./example_middleware/after1'); var after2 = require('./example_middleware/after2'); // fake request simulate /service var fakerequest = require('./example_middleware/fake_request'); // function sort order of middleware executed var sortconfig = function(confirguration){ var sortable = []; (var middleware in confirguration) // make middlewares configurable if (confirguration[middleware]['enable'] == true){ sortable.push([middleware, confirguration[middleware]['priority']]); } sortable.sort(function(a, b) {return b[1] - a[1]}); return sortable; } // var sortedconfig = []; var middlewareset = new array(); app.use('/test', function(request, response, next){ var middleware; var sortedconfig = sortconfig(confirguration); (var in sortedconfig){ switch(sortedconfig[i][0]){ case 'before1': middleware = before1; break; case 'before2': middleware = before2; break; case 'service': middleware = fakerequest; break; case 'after1': middleware = after1; break; case 'after2': middleware = after2; break; } // console.log(sortedconfig[i][0]); // execute middleware in expected order middlewareset.push(middleware); } // request.sortedconfig = sortedconfig; console.log(middlewareset); console.log('middleware list sorted'); next(); }); app.use('/test', middlewareset);
but keep getting same error message coming app.use() @ last line:
app.use() requires middleware functions
it works if use:
app.use('/test', [before1, before2, fakerequest, after1, after2]);
but it's not dynamic though, did misunderstand? there must way in express.js.
thanks in advance.
edit: modified code according ryan's answer, here code:
var async = require('async'); app.use('/test', configurablemiddleware); function configurablemiddleware(req, res, next) { var operations = []; var middleware; var sortedconfig = sortconfig(confirguration); // push each middleware want run sortedconfig.foreach(function(fn) { switch(fn[0]){ case 'before1': middleware = before1; break; case 'before2': middleware = before2; break; case 'service': middleware = fakerequest; break; case 'after1': middleware = after1; break; case 'after2': middleware = after2; break; } operations.push(middleware); // use fn.bind(null, req, res) pass in vars }); console.log('middleware list sorted'); // invoke middleware in series async.series(operations, function(err) { if(err) { // 1 of functions passed error handle here return next(err); } // no errors pass control express next(); }); }
just make sure haven't made mistakes in test middleware, here example of 1 of them:
'use strict'; var express = require('express'); var router = express.router(); router.route('/') .all(function(request, response, next){ console.log('this middleware before1'); next(); }); module.exports = router;
now, when run application, got following error npm:
typeerror: cannot call method 'indexof' of undefined
at function.proto.handle (/users/jialunliu/documents/soa_project/fat-lady/node_modules/express/lib/router/index.js:130:28) @ router (/users/jialunliu/documents/soa_project/fat-lady/node_modules/express/lib/router/index.js:35:12) @ /users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:610:21 @ /users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:249:17 @ iterate (/users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:149:13) @ async.eachseries (/users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:165:9) @ _asyncmap (/users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:248:13) @ object.mapseries (/users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:231:23) @ object.async.series (/users/jialunliu/documents/soa_project/fat-lady/node_modules/async/lib/async.js:608:19) @ configurablemiddleware (/users/jialunliu/documents/soa_project/fat-lady/app.js:135:11)
which coming line async.series(operations, function(err){})
i keep getting kind of error message, saying function not read array of functions "operations"....
i think on right track, need tweak few things. register 1 top level function app.use()
, of dynamic stuff within function. updating answer working example. sure install async first npm install --save async
// define middleware functions var middleware = { mw1: function(req, res, next) { console.log('mw 1'); next(); }, mw2: function(req, res, next) { console.log('mw 2'); next(); }, mw3: function(req, res, next) { console.log('mw 3'); next(); }, mw4: function(req, res, next) { console.log('mw 4'); next(); } }; // register our "top level function" app.use(configurablemiddleware); var requestcount = 1; // working example function configurablemiddleware(req, res, next) { var isevenrequest = requestcount++ % 2 === 0; // simple logic alternate "configurable" middleware use var operations; // in real world build array dynamically, hardcode 2 scenarios example // each request http://localhost:3000 alternate middleware used, see different log each time if(isevenrequest) { console.log('even request should log mw2 , mw4'); // .bind(null, req, res) makes sure middleware gets request , response objects when invoked, // of point still haven't been invoked... operations = [middleware.mw2.bind(null, req, res), middleware.mw4.bind(null, req, res)]; } else { console.log('odd request should log mw1 , mw3'); operations = [middleware.mw1.bind(null, req, res), middleware.mw3.bind(null, req, res)]; } // invoke each middleware in series - async.parallel if order of middleware doesn't matter // using async module: https://github.com/caolan/async async.series(operations, function(err) { if(err) { console.log('there problem running middleware!'); return next(err); } // middleware has been run next(); }); }
for more info on .bind() see https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/function/bind
Comments
Post a Comment