How to execute NodeJS function on page refresh - node.js

I wrote a small NodeJS application from an example. Heres the part of my code.
server.js:
var app = express();
var helper = require('./helpers.something.js');
helper.calculate(function(result) {
app.set('something', result);
});
var router = express.Router();
var home = require(./controllers/home.js);
router.get('/', home.index);
home.js
exports.index = (function(req, res) {
res.locals.calculations = req.app.get('something');
res.render('home', {
data: req.app.get('something');
});
};
The problem I am trying to resolve now is that helper.calculate function is called only when server is started instead of being called every time the page is refreshed. Could anyone advice me how can I call helper.calculate every time the page is refreshed if I want to use the result in both home.js and server.js files as I'm quite lost in express.js documentation.

You can create a middleware that will run the function every time that this route is accessed.
You might change this:
helper.calculate(function(result) {
app.set('something', result);
});
var router = express.Router();
var home = require(./controllers/home.js);
router.get('/', home.index);
to something like this:
var router = express.Router();
var home = require(./controllers/home.js);
const calculate = (req, res, next) => {
helper.calculate(function(result) {
app.set('something', result);
});
next();
};
router.get('/', calculate, home.index);
OR:
var router = express.Router();
var home = require(./controllers/home.js);
const calculate = (req, res, next) => {
helper.calculate(function(result) {
app.set('something', result);
next();
});
};
router.get('/', calculate, home.index);
depending on whether or not you want to wait with running the controller until the helper.calculate() finishes.
The other option would be to add this to the controller code in home.js but I assume that you don't want to do that because you would use app.set() and app.get() one after another so I guess you want to separate the act of setting the variable and using it.

Related

Using the same module for two endpoints

I'm working on an express js server for some whitelisting. I need to make two whitelists, but I don't want to just make two files for them.
var whitelistOneRouter = require('./routes/whitelist')
var whitelistTwoRouter = require('./routes/whitelist')
app.use("/whitelists/whitelistOneRouter", whitelistOneRouter)
app.use("/whitelists/whitelistTwoRouter", whitelistTwoRouter)
whitelist.js
var router = express.Router();
var Merkle = require('../modules/merkle')
var merkleOne = new Merkle([])
router.get('/', function (req, res, next) {
var address = req.body.address
var proof = merkleOne.getProof(address)
res.send(proof)
})
router.get('/root', function (req, res, next) {
res.send(merkleOne.getRoot())
})
router.post('/new', function (req, res, next) {
var whitelist = req.body.whitelist
merkleOne.setNewWhitelist(whitelist)
res.send(merkleOne.getRoot())
})
module.exports = router;
When I try to interact with one endpoint, it changes the other and vice versa. Does anyone know a better way to do this? I don't want to make another file that's the same code.
OK, I'm guessing that you want a separate instance of your Merkle class for each.
Modules are cached so they only run their own initialization just once. So, the way you had it before, you had one router and one instance of your Merkle object. To have separate instances you move the code into a function so it can be called as many times as you want and will create a new Merkle object each time. Here's one way to do that:
const Merkle = require('../modules/merkle');
const express = require('express');
module.exports = function() {
const router = express.Router();
const merkleOne = new Merkle([])
router.get('/', function (req, res, next) {
var address = req.body.address
var proof = merkleOne.getProof(address)
res.send(proof)
})
router.get('/root', function (req, res, next) {
res.send(merkleOne.getRoot())
})
router.post('/new', function (req, res, next) {
var whitelist = req.body.whitelist
merkleOne.setNewWhitelist(whitelist)
res.send(merkleOne.getRoot())
})
return router;
}
Then, use it like this:
const whiteListFn = require('./routes/whitelist');
app.use("/whitelists/whitelistOneRouter", whiteListFn());
app.use("/whitelists/whitelistTwoRouter", whiteListFn());
Modules in Node.js are essentially singletons.
Where ever you require the path that ./routes/whitelist resolves to, it will export the same merkleOne and router as they are defined in the modules outermost scope.
If you want to share the code, then exporting a factory function is one way to achieve separate instances
function newMerkleRouter(){
var merkleOne = new Merkle([])
var router = express.Router();
router.get('/', function (req, res, next) {
var address = req.body.address
var proof = merkleOne.getProof(address)
res.send(proof)
})
router.get('/root', function (req, res, next) {
res.send(merkleOne.getRoot())
})
router.post('/new', function (req, res, next) {
var whitelist = req.body.whitelist
merkleOne.setNewWhitelist(whitelist)
res.send(merkleOne.getRoot())
})
return router
}
app.use("/whitelists/whitelistOneRouter", newMerkleRouter())
app.use("/whitelists/whitelistTwoRouter", newMerkleRouter())

How to save POST to global variable in node

I am sending json by POST to nodejs, I declared router.post in index.js, (/routes)
How I can save it so I can actually use that later on? Keep in mind that every 60sec I am getting new data that should replace the old one.
I am listening on port 3000
var express = require('express');
var router = express.Router();
var saveme
/* GET home page. */
router.get('/index', function(req, res, next) {
res.render('index', { title: 'RLH' });
});
router.post('/index', function(req, res, next) {
data = req.body;
console.log('OK')
});
module.exports = router;
I don't know how can I save what I get trough POST, so later on I can use it on my website.
There are multiple ways to use Global variable:
Method1
Using app.locals :
declare app.locals.data = {}; in main file (ex:server.js)
var app = express();
app.locals.data = {};
app.locals available to req object as req.app.locals. When you have new data you can update it as :
req.app.locals.data = req.body;
Method2
Using global object
Assign new data as global.data = req.body
You can always access data as global.data in same or different module
Method3(Recommended)
Create file globaldata.js with below code
module.exports = {};
Import globaldata.js where you need to access or update global data as
var globaldata = require('./globaldata.js');
globaldata = req.body;
What is recommended? global method for small apps, module.exports for big apps.
You can read below ref. for more details:
https://www.hacksparrow.com/nodejs/global-variables-in-node-js.html
http://expressjs.com/en/api.html#app.locals
If by saving the data you mean storing it in a variable you can do:
var express = require('express');
var router = express.Router();
var saveme;
/* GET home page. */
router.get('/index', function(req, res, next) {
if (saveme) {
// you can use `saveme`
res.render('index' + saveme.toString(), { title: 'RLH' });
}
else {
res.render('index', { title: 'RLH' });
}
});
router.post('/index', function(req, res, next) {
data = req.body;
// set `saveme`
saveme = data;
});
module.exports = router;

express router with id

I know I can do this in Express:
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
to get my url parameter.
When I try to use a router logic I did:
index.js
var sites = require('./routes/sites');
app.use('/:id', sites);
routes/sites.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
module.exports = router;
this logic does not work, I get {} in the shell command, undefined for req.params.id.
Any idea where my logic is wrong?
It doesn't work, because that's just not how express interacts with its Routers. The reason you're not seeing id inside your router, is because :id was not declared within its scope. You'd need to do something like
app.use('/', sites);
and in your router
var express = require('express');
var router = express.Router();
router.get('/:id', function(req, res, next) {
console.log(req.params.id);
// etc ...
});
module.exports = router;
Additionally you can try playing around with app.param() see docs for examples http://expressjs.com/api.html#app.param
When you are trying to do this in index.js and routes.js -
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
"id" is not defined there because that's how express works with routers, it just matches the routes matching with the specified prefix in app.use() method. For that, you can try using -
const express = require('express');
const router = express.Router({mergeParams: true});
Now it will work perfectly.
It actually works now.
You can do something like
app.use('/:id/transactions', require('./routes/transactions'));
In the main file, and then add {mergeParams:true} to Router options in the controller file.
const router = require('express').Router({mergeParams:true});
So here you will be able to get the id that was set in base Route.
// localhost:5000/:id/transactions/
router.get('/',(req, res) => {
console.log(req.params.id);
}
Found here:
http://expressjs.com/api.html#app.param
In your file router/sites.js, add an option to express router:
const router = express.Router({mergeParams:true});
Now you have access to id in sites.js file.

Recursive Expressjs Routing

Without resorting to regular expression is there anyway with expressjs to recursively call routing ie url examples:
/f:forum/s:section/t:thread/p:post
/f:forum/s:section/s:section/t:thread/p:post
/f:forum/s:section/s:section/s:section/t:thread/p:post
...
Therefore allowing technically an infinite amount of "sections/subsections" in the forum.
I attempted to do:
app.js:
var express = require('express');
app = express();
app.route('/').get(function(req, res, next){
return res.send('hello');
});
app.use('/f:forum', require('./section'));
server = app.listen(process.env.http || process.env.PORT);
module.exports = app;
section.js:
var router = require('express').Router();
router = router;
router.route('/s:section').get(function(req, res, next){
return res.send(req.params);
});
router.use('/s:section', require('./thread'));
module.exports = router;
thread.js:
var router = require('express').Router();
router.use('/s:section', require('./section'));
router.route('/t:thread/p-:post').get(function(req, res, next){
return res.send(req.params);
});
router.route('/t:thread').get(function(req, res, next){
return res.send(req.params);
});
module.exports = router;
but interestingly it tells me that in thread.js require('./section') = {}
yet in app.js it is correct... any suggestions?
You can do wildcard routing like router.route('/:path*') and then have the handler parse from that point down.
For example, something like:
router.route('/forum/:path*', function(req,res){
var requestPath = req.path; // will present the whole path to you for parsing
// do whatever db lookup logic you normally would do now that you have the pieces you wanted
res.render('forum', data);
};

Pass configuration to controller

I am building a node.js app that will upload files to my S3 bucket using knox. I am able to interact with S3 as expected, but I would like to make my controller to receive configuration so I can dynamically construct my client with configuration values.
My questions is how do I get configuration paramters down the call stack to my controller without being careless?
Disclaimer: I am rather new to Node.js so it could be simply my lack of knowledge in the difference between exports. and module.exports.*
Here is an example of how the interaction works with my code:
app.js
...
config = require('./config/config')['env'];
require('./config/router')(app, config);
...
router.js
module.exports = function(app, config) {
...
var controller = require('../app/controllers/home'); //Is there a way for me to pass config here?
app.post('/upload', controller.upload); //Or here?
...
}
home.js
var knox = require('knox');
var client = knox.createClient({ ... }); //I want to use config.key, config.secret, etc instead of hard-coded values
...
exports.upload = function(req, res) {
//Use client
}
...
Try doing something like this...
var config = require('./config/config')['env'];
// The use function will be called before your
// action, because it is registered first.
app.use(function (req, res, next) {
// Assign the config to the req object
req.config = config;
// Call the next function in the pipeline (your controller actions).
return next();
});
// After app.use you register your controller action
app.post('/upload', controller.upload);
And then in your controller action...
exports.upload = function(req, res) {
//Your config should be here...
console.log(req.config);
}
Ps. I can not try it right now, but I solved a similar issue like this.
You can pass the configuration in as a parameter to you controller
Controller
// controller.js file
module.exports = function(req, res, config) {
console.log('config parameter passed to controller', config);
res.end('config passed')
}
App
// index.js file with the express app
var controller = require('./controller');
var config = {
key1: 'foo'
};
var express = require('express');
var app = express();
var port = 3000;
app.get('/', function(req, res){
controller(req, res, config);
});
app.listen(port);
console.log('app listening on port', 3000);
Demo
You can check out the github repo for a complete example
Alternative approach if you want to call multiple functions from one single route, this will do it.
Route
var users = require('../controllers/users');
app.route('/login').post(function(req, res){
if(users.authenticate()){
console.log('valid user');
if(users.createUser())
{
console.log('user created');
}
}
});
Controller
exports.authenticate = function(req, res, next) {
return true;
};
exports.createUser = function(req, res, next) {
return true;
};

Resources