Using the same module for two endpoints - node.js

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())

Related

I wanted to automate the model and route parts in node.js express

I wanted to automate the model and route parts in node.js express.
For example, the index.js of routes originally looked like this.
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', {title:'Express' });
});
router.get('/a1', function(req, res, next) {
res.render('a1', {title:'Repetitive router.get' });
});
router.get('/a2', function(req, res, next) {
res.render('a2', {title:'Repetitive router.get' });
});
router.get('/a3', function(req, res, next) {
res.render('a3', {title:'Repetitive router.get' });
});
module.exports = router;
I don’t want to hard-code this every time
router.get function part
var express = require('express');
var router = express.Router();
var AAA = require('myGetAll');
AAA.add('/a1', a1, {title:'Repetitive router.get' });
AAA.add('/a2', a2, {title:'Repetitive router.get' });
AAA.add('/a3', a3, {title:'Repetitive router.get' });
/* GET home page. */
for(let i = 0; i <AAA.count(); i++){
router.get(AAA.itemPath[i], function(req, res, next) {
res.render(AAA.itemFile[i], AAA.itemParameter[i]);
});
}
module.exports = router;
I would like to do it this way.
Would it be okay to do this?
if not
MVC like express, but
Recommend a framework with better code automation.
Thank you.
There is a good way you could achieve this using route params.
router.get('/:param(a+[1-3])', function(req, res, next) {
const parameter = req.params.param;
res.render(parameter, {title:`Repetitive router.get this ${parameter}` });
});
You can pass an optional regular expression to the route to match the desired param, or just handle the input inside your code logic (in this case i´ve added a regex to match a1-a3)
https://expressjs.com/en/guide/routing.html

How to execute NodeJS function on page refresh

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.

Grouping routes in Express

We can group our routes like this in Laravel:
Route::group("admin", ["middleware" => ["isAdmin"]], function () {
Route::get("/", "AdminController#index");
Route::post("/post", ["middleware" => "csrf", "uses" => "AdminController#index");
});
Basically, all the routes defined in admin group gets the isAdmin middleware and group name automatically. For example, post endpoint listens to admin/post not /post
Is there any way to do the same thing with Express? It would be awesome because my Laravel routes used to be so clean, whereas my Express routes are a bit messy/duplicated.
This is my routes.js on Express at the moment.
app.get("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.index);
app.post("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.postIndex);
Thank you.
Since express 4 you can define and compose routers
const app = require('express');
const adminRouter = app.Router();
adminRouter.use(isAdmin);
adminRouter.get('/', admin.index); /* will resolve to /admin */
adminRouter.post('/post', csrf, admin.index); /* will resolve to /admin/post */
app.use('/admin', adminRouter);
Hope that helps!
Just use before of every group you want to do:
app.use('/admin', AdminMiddleware);
app.get('/admin/route1', ...
app.get('/admin/route2', ...
app.use('/user', UserMiddleware);
app.get('/user/route1', ...
app.get('/user/route2', ...
require('express-group-routes');
var app = require('express');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
In case you don't want to add a prefix but still need to group certain routes you can leave the first parameter and go straight for the function:
require('express-group-routes');
var app = require('express');
app.group((router) => {
router.use(middleware);
});
You can use app.use() - https://expressjs.com/en/guide/using-middleware.html#middleware.application
app.use("/admin",[passportConfig.isAuthenticated, passportConfig.isAdmin],AdminController)
// AdminController:
var express = require('express');
var router = express.Router();
router.get('/', AdminController.index);
// etc...
module.exports = router
https://expressjs.com/en/guide/routing.html#express-router
I found some better solution you can follow this method it's working good
Route file route/user.js
var express = require('express')
var router = express.Router()
const authMiddleware = require('../middleware/auth')
express.application.prefix = express.Router.prefix = function(path, middleware, configure) {
configure(router);
this.use(path, middleware, router);
return router;
}
router.prefix('/user', authMiddleware, async function (user) {
user.route('/details').get(function(req, res) {
res.status(201).send('Hello this is my personal details')
}); //also you can use controller method if you have any
});
module.exports = router //make sure you have to import/use this route in main/server js
You can use an npm module
Express group route
here is a code example from npm official module
var app = require('express');
require('express-group-routes');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
Create the group method
export const group = ((callback: (router: Router) => void) => {
const router = express.Router();
callback(router);
return router;
});
Use the group method
import { group } from './relative/path/to/group/method'
const apiRouter = express.Router();
apiRouter.use('/foo', group((router) => {
router.get('/bar', (req, res) => {
res.send('Hello World');
});
}));
This will create a new GET route to "/foo/bar"
I just wrote this module to solve your problem: https://github.com/benjamin658/express-inject-middleware
You can group your middlewares as an array and pass it to the express-inject-middleware...
For example:
import express from 'express';
import { injectMiddleware } from 'express-inject-middleware';
const app = express();
const authMiddleware = (req, res, next) => {
// some auth logic...
};
const fooMiddleware = (req, res, next) => {
// some foo logic
}
const barMiddleware = (req, res, next) => {
// some bar logic
}
app.use(injectMiddleware(
[
authMiddleware,
fooMiddleware,
],
[
// Passing the app.[METHOD] as the parameter.
app.get('/secrets', (req, res, next) => res.send('secrets'));
// Mount barMiddleware itself
app.post('/secrets', barMiddleware, (req, res, next) => res.send('ok'));
],
));
and this is the result:
app.get('/secrets', authMiddleware, fooMiddleware, (req, res, next) => res.send('secrets'));
app.post('/secrets', authMiddleware, fooMiddleware, barMiddleware, (req, res, next) => res.send('ok'));
in express 4 to grouping your routes, you should create some changes :
seperate route files in multiple files like admin and front
pass the router to the divided route files in routes/index.js file
const express = require('express')
require('express-group-routes');
const router = express.Router()
require('./admin/web.router')(router)
require('./front/web.router')(router)
module.exports = router
in each files we can use groups, middlewares and prefixes, like below
const adminPrefix = 'admin'
module.exports = function (router) {
router.use(`\${adminPrefix}`, [ adminMiddleware ]);
router.group(`/${adminPrefix}`, (router) => {
router.get('/', home.index)
});
}

How to pass multiple parameters from controller in node.js express

I am working with Passport, and I need to pass multiple parameters through to from my controller to my router. Basically it only passes the first one.
I want to get
app.get('/auth/steam', controllers.auth.authenticate);
to result in
app.get('/auth/steam', passport.authenticate('steam'), function(req, res) { res.render('index') };);
Right now it only loads the 1st parameter.
My controller looks like this
exports.authenticate =
passport.authenticate('steam'),
function(req, res) {
res.render('index');
};
How would I do this?
EDIT: I want to only be able to call it with controllers.auth.authenticate, not in an array like: controllers.auth.authenticate[0]!
Warning NOT tested.
You can wrap all inside function
exports.authenticate = function(req, res, next) {
passport.authenticate('steam', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/auth/steam'); }
res.render("index");
});
}
Or you can use router and protect ALL verbs (get, post, etc)
var express = require('express');
var router = express.Router();
router.use(function (req, res, next) {
passport.authenticate('steam');
});
router.get('/', function(req, res, next) {
res.render("index");
});
module.exports = router;
And use router on the app
var ctrl = require("yourModuleName");
app.use('/auth/steam', ctrl); // app.use NOT app.get
Other alternative is to protect only the get
var express = require('express');
var router = express.Router();
router.get('/', passport.authenticate('steam'), function(req, res, next) {
res.render("index");
});
module.exports = router;
var ctrl = require("yourModuleName");
app.use('/auth/steam', ctrl); // app.use NOT app.get
See Express routing page

get REST APi response in another route

I'm using Express with generator
I want to use JSON response of Rest Api in another route
like this :
var express = require('express');
var router = express.Router();
router.get('/api/:id', function(req, res, next) {
res.json($something); // generate json object
});
router.get('/show', function(req, res, next){
router.get(/api/12,function(request, response){
res.send(request.body);
});
});
Either you extract the middleware function used for /api/:id/ so you can reuse it (recommended) or you need to issue a proper request. router.get does not request the resource, as you seem to think, it rather sets up a route.
So, I'd go for:
var express = require('express');
var router = express.Router();
var getResource = function(req, res, next) {
//use req.params.id to look up resource
res.json($something); // generate json object
}
router.get('/api/:id', getResource );
router.get('/show', function(req, res, next){
req.params.id = "12";
return getResource(req, res, next);
});

Resources