How will I pass values from router to controller in nodejs - node.js

I want to pass app.locals values into a controller function. How will I pass the variable inside the controller.
var enroll_controller=require('../enrollController');
router.post('/enroll',function(req,res){
var contractAddress=req.app.locals.contractAddress;
enroll_controller.newUser
});
I want to pass contractAddress to enroll_controller?
Anybody?

You can try this too if you don't want to use middleware.
var enroll_controller=require('../enrollController');
router.post('/enroll',function(req,res){
enroll_controller.newUser(req,res);
});
enrollCntroller.js
exports.newuser=function(req,res){
var contractAddress=req.app.locals.contractAddress
}

pass it as middleware:
router.post('/enroll',enroll_controller.newUser);
And in your controller function you can directly use it like this:
exports.newUser=function(req,res){
var contractAddress=req.app.locals.contractAddress
}

You can write a global middleware and set these values in that middleware if you want it to be available for every route.
// in your app.js file or main file which is wiring up application
app.use(function(req,res,next){
req.app.locals.contractAddress = "Set address here."
next();
});
var enroll_controller=require('../enrollController');
router.post('/enroll',enroll_controller.newUser);
or you can export run the above middleware to only one route and set address for that specific route.
var enroll_controller=require('../enrollController');
router.post('/enroll',
function(req,res, next){
// middleware running to one route only.
req.app.locals.contractAddress = 'set address here';
next();
},
enroll_controller.newUser
);
You can also export this middleware from a file and then reuse it instead of defining for every time as anonymous function.

Related

Express.js unique var per request outside routing

In my express application I have a module called helpers thats is required in almost all my routes and modules. This module has a logger method that logs to fluentd (but that's unimportant). While building the data to log I'd like to add a unique identifier of the request, so that all the logs written for the same request have the same unique ID. Using a global var in the app entry point app.use doesn't work because this var would be overwritten every time a new request hits, so the global uuid will change would obviously change in case of high load or long running tasks. The res.locals is not available outside routing, so I can't use it for this matter. Is there a way to create a var that would be unique per request and available in every module or maybe a way to access the res.locals data outside routing? Thank you
EDIT
Maybe an example will help understand better the question.
Suppose I have a module called helpers.js like this:
let helpers = {};
helpers.log = (logData, logName) => {
fluentLogger.emit('', {
name: logName,
//uuid: the needed uuid,
message: logData
});
}
module.exports = helpers;
Now obviously I can do this in my app.js entry point:
app.use(function (req, res, next) {
res.locals.uuid = uuid.v4();
next();
});
and then in every loaded middleware module that requires helpers(adding a new param to the helpers.log method):
const helpers = require('helpers');
router.post('/', (req, res, next) => {
helpers.log('my log message', 'myLogName', res.locals.uuid);
next();
});
and this will normally work. But suppose a big or middle size project where there are hundreds of custom modules and models (not middlewares) and a module may require other modules that require other modules that require finally the helpers module. In this case I should pass the res.locals.uuid as a parameter to every method of every method so that I have it available in the logger method. Not a very good idea. Suppose I have a new module called dbmodel.js that is required in a middleware function:
const helpers = require('helpers');
let dbmodel = {};
dbmodel.getSomeData = (someParam) => {
//some logic
helpers.log('my log message', 'myLogName');
}
module.exports = dbmodel;
The dbmodel has no idea about the res.locals data if I don't pass it from the middleware, so the helpers.log method will also have no idea about this.
In PHP one would normally write a GLOBAL var in the application's entry point so a hypothetical logger function would have access to this global on every method request from whichever class of the application.
Hope this explanation will help :) Thank you
EDIT 2
The solution for this kind of problems is CLS. Thanks to #robertklep for the hint. A good slideshare explaining exactly the same problem (logger with unique ID) and explaining the CLS solutions can be found here: https://www.slideshare.net/isharabash/cls-and-asynclistener
I answered a very similar question here which will solve this problem.
I used to solve the problem the libraries node-uuid and continuation-local-storage. Take a look to the answer of this question and see if it helps:
NodeJS Express - Global Unique Request Id
And you want a bigger explanation, take a look here:
Express.js: Logging info with global unique request ID – Node.js
Yes you can do so by one method .
Every request comes to his routes pass that request inside the middleware.
Suppose you have
app.get('/', function(req, res) {
res.sendFile(path.join(public + "index.html"));
});
a request.
Place Middleware in it .and edit req field coming , in this way you will get the unique variable values for each request
check out this .
https://expressjs.com/en/guide/writing-middleware.html
Like this
var requestTime = function (req, res, next) {
req.requestTime = Date.now()
next()
}
app.use(requestTime)
app.get('/', function (req, res) {
var responseText = 'Hello World!<br>'
responseText += '<small>Requested at: ' + req.requestTime + '</small>'
res.send(responseText)
})
Here req.requestTime is unique for each request.

Express 4 router.param doesnt fire

I have a node express 4 app and I want to mount a route (contacts) on a parent route. i.e
/:fundid/contacts
In my fund route I declare
var router = require('express').Router({ mergeParams: true });
var contactRoutes = require('./contacts');
router.use('/:fundid/contacts', contactRoutes);
In my contact route
var router = require('express').Router({ mergeParams: true });
router.param('fundid', function(res, req, next, id){});
The problem is that this param call does not fire. From what I can garner from the documentation these param calls are relative to the router they are declared on, but i would have thought mergeParams:true would affect this, but it doesn't. The route is otherwise working, and both routes are called. Am I missing something?
The reason I want to do this is because I want to mount the contacts route on multiple parent routes, and build a filter based on those parent parameters
This comment suggests that parameters are tied to the router they are declared with; so in your case, fundid can only be handled by the "fund" router. mergeParams serves a different purpose, namely to provide access to req.params.fundid from child routers.
You can always use a request middleware in your contact router to perform special operations based on the fundid, though:
router.use(function(req, res, next) {
var id = req.params.fundid;
...
});

Node Express auth status

I have multiple routes, split into different files (my app consists of different "modules", which I maintain in separate folders. For each folder, there is an index.js file in which I manage the routes per module, and I require these in the app.js file).
For every route, I will require to check the auth, and pass the loggedIn status to the header of every page:
//Default variables for the ejs template
var options = {
loggedIn: true
};
res.render("home/home", options);
If the logged in status is true, then the user's name will be displayed. If not, the login / signup labels are displayed.
What is the best way to centralise this, so that I don't need to require the auth script in every of these index.js (route) files?
I need to be able to pass the auth status to the view via the options object (see example).
In your auth, module, use a middleware function. That function can check and store res.locals.loggedIn which will be available for any view that will eventually be rendered. Just make sure the app.use call executes prior to your other routes and it will work properly.
app.use(function auth(req, res, next) {
res.locals.loggedIn = true; // compute proper value here
next();
});
From what I understand you need to do this for every request.One common thing is adding this as middleware so that all the request gets this .
For Example :
var http = require('http');
var connect = require('connect');
var app = connect();
app.use(function(req, res) {
res.end('Hello!');
});
http.createServer(app).listen(3000)
Now for every request , Hello is printed . You could extract this as a module and reuse it across projects. Check here for more details

Node.js variables for current request only?

I am very new to Node.js, and I was wondering if that, except for session(), I could use a "storage" to store variables for the current request?
I have an API which is based on an Authorization header, and a pool of valid tokens stored in Redis.
Therefore I don't have a session and don't want to.
But I would like to store variables for further use during this request. For example, I would like to store the user_id corresponding to the token found in Redis, so that I can use it wherever I want.
If I do something like:
app = express();
app.user_id = 1;
Is it ok, or will my user_id become global to all requests handled by the app? (in short: is the app instanciated for each request handled by the server, or is it persistent?)
If this is not ok, how could I achieve something like this without sessions?
Thank you for any help :)
The app handles all requests, and would only be created once on startup, but req lives for only the lifetime of the request. Keep in mind that the req in Express is just an object, and as such, can be assigned values. So if you wanted to allow the controller to have access to some value (similar to sessions), you could do something like this:
var express = require('express');
var app = express();
// middleware that assigns a value '123' to 'req.user_id'
app.use(function(req, res, next) {
req.user_id = 123;
next();
});
// controller which responds with the 'req.user_id'
app.get('/hello', function(req, res){
res.send('req.user_id: ' + req.user_id); // responds with req.user_id: 123
});
app.listen(3000, function() {
console.log('Listening on port 3000');
});
In the above example, the middleware that I created assigns a value to the request, called user_id. This value lives for the life of the request. You could do a similar thing to assign a dynamic value to the req so that you can access it via your controllers.

Global variable across all controllers in Node JS

I am trying to have a variable which can be accessible by all controllers in my node project. Currently in one controller I have:
var ua = req.headers['user-agent'];
var isMobile = "no";
if(/mobile/i.test(ua))
isMobile="yes";
It's pointless to copy past all of this for all my controllers and pass the isMobile variable to the view. I'd like to get the value of isMobile set once, and then pass it wherever I want from my controllers.
Is there an easy way to do this rather than have those 4 lines of code copy pasted in every controller?
Thanks
You'll want to use a Sails policy for this:
// /api/policies/isMobile.js
module.exports = function(req, res, next) {
var ua = req.headers['user-agent'];
req.isMobile = /mobile/i.test(ua);
next();
}
// /config/policies.js
module.exports.policies = {
'*': 'isMobile'
};
This will run the code before every controller action, and give you access to the req.isMobile var in all of your custom controller code.
A truly global variable isn't particularly an option as any concurrency above 1 will likely result in unexpected behavior. Being that it is something particular to the unique request itself, the req object is likely your best bet.
Assuming you have access to the req object everywhere that you would like to utilize use this flag, you can simply add a property to the req object at any point (preferably early in the request/response cycle). After this property is added, it should be available everywhere that has access to req.
req.isMobile = /mobile/i.test(req.headers['user-agent']) ? 'yes' : 'no';
Or if there is a concept like middleware in express for sails
function isMobile(req, res, next) {
req.isMobile = /mobile/i.test(req.headers['user-agent']) ? 'yes' : 'no';
next();
}

Resources