Cannot pass params between middlewares - node.js

I've searched for a way to pass data between middlewares in Express, and I've found this. Basically, the solution given is to create req.somevariable = variable1;.
As is told in the comments, req.somevariable throws undefined and the possible solution cosists on creating a previous middleware to initialize that variable.
Is there any simplier solution? I've also tried to do:
req.body.myVar = myVar;
But I still have the error about the var is undefined.
Thanks.

You can pass it easily. Just store it req object.
app.get('/user', function(req, res, next) {
req.id = "123456789";
next();
}, function (req, res, next) {
var id = req.id;
// do your working
});

Related

ExpressJS: Is it possible to share variables between different routing functions for the same route?

While getting and processing query parameters within different routing functions, it is necessary to define the same thing within each routing function.
router.get("/", function(req, res, next){
var processed_query = process_function(req.query);
//do some thing based on the query string
console.log(processed_query);
next();
}, function(req, res, next){
var processed_query = process_function(req.query); //this needs to be defined again
//do some different thing based on the query string
res.write(JSON.stringify(processed_query));
});
While it is understandable to do it this way because the functions' scopes are different, it seems a bit superfluous and against the general rule of don't repeat yourself to have to repeatedly define the same variable var processed_query = process_function(req.query); for the exact same req. Is there a (better) way of doing it just once?
You can store your calcuated variable in some property of req object. E.g.
router.get("/", function(req, res, next){
var processed_query = process_function(req.query);
//do some thing based on the query string
console.log(processed_query);
req.processed_query = processed_query;
next();
}, function(req, res, next){
var processed_query = req.processed_query;
//do some different thing based on the query string
res.write(JSON.stringify(processed_query));
});

I would like to add a query param apikey for all my external call

I have a server in express and it uses an external api. I would like for each request to that api ('/api/*'), that it appends a query param in the url without to write it for each requests.
app.use(function(req, res) {
req.query.key = process.env.APIKEY;
});
I tried something like that but it doesn't work.
I thought of doing something like :
app.get('/api/stuff', addApiKey, api.stuff);
Is there a better way?
You need to supply your middleware function with a next callback:
function addApiKey(req, res, next) {
req.query.key = process.env.APIKEY;
next();
});
app.get('/api/:endpoint', addApiKey, function(req, res) {
// do your stuff here
});

Node.js Express nested resources

i'd like to nest resources like the below eg.
/// fileA.js
app.use('/dashboards/:dashboard_id/teams', teams);
[...]
///teams.js
router.get('/', function(req, res, next) {
[...]
}
but I can't get the req.params["dashboard_id"] parameter in teams because it seems it is already substituted with the parameter value.
I've tried to baypass the problem by calling an intermediate function and pass somewhere the parameter but I can't figure out where ...
Do you have an answer?
Thanks,
Franco
You may try this solution:
//declare a function that will pass primary router's params to the request
var passPrimaryParams = function(req, res, next) {
req.primaryParams = req.params;
next();
}
/// fileA.js
app.use('/dashboards/:dashboard_id/teams', passPrimaryParams);
app.use('/dashboards/:dashboard_id/teams', teams);
///teams.js
router.get('/', function(req, res, next) {
var dashboardId = req.primaryParams['dashboard_id']; //should work now
//here you may also use req.params -- current router's params
}
Using Express 4.0.0 or above at the time of this writing:
To make the router understand nested resources with variables you will need create and bind a new router using app.use for every base path.
//creates a new router
var dashboardRouter = express.router();
//bind your route
dashboardRouter.get("/:dashboard_id/teams", teams);
//bind to application router
app.use('/dashboards', dashboardRouter);
This way Express will see the first part of the path and go to the /dashboards route, which has the :dashboard_id/teams path.
You can use the mergeParams option here
// fileA.js
app.use('/dashboards/:dashboard_id/teams', teams);
// teams.js
const router = express.Router({ mergeParams: true })
router.get('/', function(req, res, next) {
// you will have access to req.params.dashboard_id here
}
You can also see this answer: Rest with Express.js nested router

How do I combine Connect middleware into one middleware?

I have a few middlewares that I want to combine into one middleware. How do I do that?
For example...
// I want to shorten this...
app.use(connect.urlencoded())
app.use(connect.json())
// ...into this:
app.use(combineMiddleware([connect.urlencoded, connect.json]))
// ...without doing this:
app.use(connect.urlencoded()).use(connect.json())
I want it to work dynamically -- I don't want to depend on which middleware I use.
I feel like there's an elegant solution other than a confusing for loop.
Express accepts arrays for app.use if you have a path:
var middleware = [connect.urlencoded(), connect.json()];
app.use('/', middleware)
However, if you want a generic combineMiddleware function, you can build a helper easily without any additional libraries. This basically takes advantage of the fact that next is simply a function which takes an optional error:
/**
* Combine multiple middleware together.
*
* #param {Function[]} mids functions of form:
* function(req, res, next) { ... }
* #return {Function} single combined middleware
*/
function combineMiddleware(mids) {
return mids.reduce(function(a, b) {
return function(req, res, next) {
a(req, res, function(err) {
if (err) {
return next(err);
}
b(req, res, next);
});
};
});
}
If you like fancy stuff, here is one of possible solutions:
var connect = require('connect')
var app = connect()
function compose(middleware) {
return function (req, res, next) {
connect.apply(null, middleware.concat(next.bind(null, null))).call(null, req, res)
}
}
function a (req, res, next) {
console.log('a')
next()
}
function b (req, res, next) {
console.log('b')
next()
}
app.use(compose([a,b]))
app.use(function (req, res) {
res.end('Hello!')
})
app.listen(3000)
Here is what it does: compose function takes array of middleware and return composed middleware. connect itself is basically a middleware composer, so you can create another connect app with middlewares you want: connect.apply(null, middleware). Connect app is itself a middleware, the only problem is that it doesn't have a next() call in the end, so subsequent middleware will be unreachable. To solve that, we need another last middleware, which will call next : connect.apply(null, middleware.concat(last)). As last only calls next we can use next.bind(null, null) instead. Finally, we call resulting function with req and res.
Old question, but the need is still frequent for all the things using middlewares, like connect, express or custom made req/res/next patterns.
This is a very elegant and purely functional solution:
File ./utils/compose-middleware.js:
function compose(middleware) {
if (!middleware.length) {
return function(_req, _res, next) { next(); };
}
var head = middleware[0];
var tail = middleware.slice(1);
return function(req, res, next) {
head(req, res, function(err) {
if (err) return next(err);
compose(tail)(req, res, next);
});
};
}
module.exports = compose;
The final result of the compose(middlewareList) is a single middleware that encapsulates the whole chain of middleware initially provided.
Then simply import it and use like this:
File app.js:
var connect = require('connect');
var compose = require('./utils/compose-middleware');
var middleware = compose([
connect.urlencoded(),
connect.json()
]);
var app = connect();
app.use(middleware);
A simple and native way, and you don't need to install anything.
const {Router} = require('express')
const combinedMiddleware = Router().use([middleware1, middleware2, middleware3])
Then you can use the combinedMiddleware where you want. For example, you may want to run different set of middlewares/handlers for the same route depending on some conditions (a request attributes, for example):
app.get('/some-route', (req, res, next) => {
req.query.someParam === 'someValue'
? combinedMiddleware1(req, res, next)
: combinedMiddleware2(req, res, next)
})
If you're willing to use a library:
https://www.npmjs.org/package/middleware-flow
var series = require('middleware-flow').series;
var app = require('express')();
app.use(series(mw1, mw2, mw2)); // equivalent to app.use(mw1, mw2, mw3);
Make a list and use a loop.
const connect = require('connect')
const { urlencoded, json } = require('body-parser')
const app = connect()
[ urlencoded(), json() ].forEach(app.use, app)
The second argument of .forEach is used for this, but if you like you can also do the same with:
[ urlencoded(), json() ].forEach(app.use.bind(app))

Node.js pass variable to route

I have very simple node.js noob question. How do I pass a variable to an exported route function?
Routes file
exports.gettop = function(n, req, res) {
console.log(n);
res.send(200);
};
Server file
app.get('/api/v1/top100', routes.gettop(100));
Error: .get() requires callback functions but got a [object Undefined]
For your example, you want to create a new function that will close around your value of n. In your case, you are executing gettop and passing the returned value to express as your route, which means gettop needs to return the route handler.
exports.gettop = function(n){
return function(req, res) {
console.log(n);
res.send(200);
};
};
As your code looks like you're using express you can use express app locals and express result locals to pass variables to your route. While the other answers propose working solutions I think that it's less obtrusive to use express mechanisms to set these variables.
With response locals (See Express API reference) you first have to set a variable somewhere in a middleware or route. I'll show the middleware approach
app.use(function(req,res, next) {
res.locals.top = 200;
next();
});
then in your route you can access this property via res.locals.variablename
exports.gettop = function(req, res) {
console.log(res.locals.top);
res.send(200);
};
In case you want to make these settings application wide a better approach is to use app locals (See Express API reference)
To set an app locals variable you can use
app.locals.top = 100;
To access this variable from your route use
exports.gettop = function(req, res){
console.log(req.app.locals.top);
res.send(200);
};
As an alternative to loganfsmyth's (very valid!) solution, you could leave your gettop function as-is and create a partial function:
app.get('/api/v1/top100', routes.gettop.bind(null, 100));
Try
app.post('/find_user',
require('./naas/autentication'),
require('./naas/authorization')(paramForRouter),
require('./routes/users'));
Where
require('./naas/autentication') is for example
module.exports = function (req, res, next) {next();}
And require('./naas/authorization')(paramForRouter) is
module.exports = function (paramForRouter) {
return function (req, res, next) {
this.param = paramForRouter;
console.log("Param value",this.param);
next();
};
};

Resources