Remove Router From Express.js Route Stack - javascript

I have an Express.js project where I am allowing plugins to be loaded and unloaded at runtime. Plugins have access to the Expess.js router stack to register their paths just like a normal script would such as:
var express = require('express');
var router = express.Router();
module.exports = function(projectCoreObject) {
function Plugin() { }
// Plugin initialize called when a plugin is loaded.
Plugin.Initialize = function (done) {
// Register the router..
projectCoreObject.app.use('/', router);
};
// GET - /test
router.get('/test', function(req, res, next) {
res.send('Success!');
});
return Plugin;
};
While this all works great, I have the issue with unloading plugins removing their router from the stack.
Is there a proper way to remove a full router object from Express.js' stack at runtime? I can do individual middleware using their names but with a route like this example shows, the name is just 'router' in the stack.

I resolved this by using a named function trick to take an anonymous function and turn it into a named one. This way I can remove the router by its name then.

Related

Split express controller into multiple files

I have a express js controller file created like this
Path: /controllers/usersController.js
// Register User
module.exports.register = function(req, res) {
...
}
// Login User
module.exports.login = function(req, res) {
...
}
// Forgot Password
module.exports.forgot_password = function(req, res) {
...
}
And I am using require() inside route file like this
Path: /routes/users.js
const usersController = require('../controllers/usersController')
router.post('/users/register', usersController.register)
router.post('/users/login', usersController.login)
router.post('/users/forgot_password', usersController.forgot_password)
This is all working fine. But my controller code is getting bigger and I want to split the userController.js into separate files so that I can have something like this
/controllers/users/index.js
/controllers/users/register.js
/controllers/users/login.js
/controllers/users/forgot_password.js
And /controllers/users/index.js needs to be the base controller which includes all these separate files. And I can simply use this index.js file into the router.
I am not sure how that is done. I tried doing module.export() method inside each separate js files and imported them inside /users/index.js file, but I am getting this error from router.
.post() requires callback functions but got a [object Undefined] not working
Note: I am not allowed to use es6 import statement :(
From whatever information I gathered from the question, you can split up the controller file by setting the module.exports to a required function in each separate file.
For example, for the /controllers/users/register.js
module.exports = function(req,res){...}
And then inside the /controllers/users/index.js
let register = require('./register.js');
router.post('/users/register', register);
And continue similarly for each controller function.

How to pass a middleware function for authentication from the main server module to a router file

Somewhat new, please bear with me. Trying to use passport to authenticate only specific routes in a website. The routes are in a separate file called blog_a.js. I have the following functions created in the main server.js file:
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()){
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()){
return res.redirect('/')
}
next()
}
However, I'm trying to pass the above functions into the blog_a.js module, so I can use them as middleware to protect the routes within that module.
I have tried to use module.exports = {checkAuthenticated, checkNotAuthenticated} at the bottom of the main 'server.js' file, and then use a let server = require('../server.js') line to import these functions to the module that contains the routes I want to protect.
However, the above server variable comes back as undefined, and I've tried several permutations / destructuring methods to try to import it. All to no avail, I keep getting the routes failing due to the "undefined" object--Error: Route.get() requires a callback function but got a [object Undefined].
How can I set up the authentication in the server.js file but then pass its authentication functions to be used as middleware within an individual route file?
I looked at this solution, but it doesn't clearly explain how to get the middleware functions from one module--server.js--to another module--blog_a.js.
I got the following response on Patreon from Kyle of Web Dev Simplified, and it worked like a charm!
"You should be able to just create another file that is called authMiddleware.js or something like that. Then in that file define and export the functions at the end (module.exports = { function1, function2 }). Now in the places you need those functions you should be able to import them like so (const { function1, function2 } = require('./authMiddleware'))."
So I followed Kyle's advice and created the following separate file authMiddleware.js:
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()){
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()){
return res.redirect('/')
}
next()
}
module.exports = { checkAuthenticated, checkNotAuthenticated }
... and then used the following require statements to get access to the functions:
-in main server.js --> const {checkAuthenticated, checkNotAuthenticated} = require('./authMiddleware.js')
-in router file blog_a.js --> const {checkAuthenticated, checkNotAuthenticated} = require('../authMiddleware.js')
Thanks!

Running Code When a Module is Loaded and Exposing It as Middleware

I am still trying to fully understand how exporting and importing modules works in Nodejs.
I am using the following file to seed a mongodb database. This file runs exactly as it should and returns exactly the result I am expecting, when I execute it as a standalone file. My issue is I want to use this file in two different places in my app. So I am trying to make it an exportable/importable module. Here is what I have tried:
seed.js looks like this:
'use strict';
// library modules
const {ObjectID} = require('mongodb');
const seeder = require('mongoose-seed');
const jwt = require('jsonwebtoken');
const util = require('util');
// local modules
const {Course} = require('./../models/course');
const {Review} = require('./../models/review');
const {User} = require('./../models/user');
const {data} = require('./../data/data.js');
const config = require('./../config/config.js');
/*==================================================
build seeding Courses, Reviews, Users
==================================================*/
// Connect to MongoDB via Mongoose
let seed = seeder.connect(process.env.MONGODB_URI, (e) => {
console.log(`Connected to: ${process.env.MONGODB_URI} and seeding files`);
// Load Mongoose models
seeder.loadModels([
'src/models/user.js',
'src/models/review.js',
'src/models/course.js'
]);
// Clear specified collections
seeder.clearModels(['User', 'Review', 'Course'], function() {
// Callback to populate DB once collections have been cleared
seeder.populateModels(data, function() {
seeder.disconnect();
});
});
});
module.exports = seed;
Within app.js I have these two lines
const seed = require('./middleware/seed');
and
app.use(seed);
I have also tried, to no avail
app.use(seed());
What is missing? I don't want to use the code in-line in two different places (DRY you know).
It is failing with this error:
throw new TypeError('app.use() requires a middleware function')
I am sorry about the formatting I thought I was using markdown, but I am clearly not.
You are executing your seeder function in that module and not returning any middleware function at all. Middleware is always a function and it has the form of:
const seed = function (req, res, next) {
...
next()
}
With what you have now, the best you can do is the following which will certainly seed your models when the module is loaded.
const seed = require('./middleware/seed');
Are you trying to run those two functions as middleware, on every request? In that case you'd do something like this:
const seed = function (req, res, next) {
seeder.connect(..., (e) => {
...
seeder.clearModels(..., ()=>{
...
next()
})
})
})
If you want to run that seeder code at the module level AND to expose it as middleware then wrap the current module level code in function and execute it when the module loads. Notice that the new function optionally handles the next callback if it receives it.
function doSeed(next){
//your code currently running at module level
if(next)
return next()
}
doSeed(); //run the code at the module level
const seed = (req, res, next) => doSeed(next))
module.exports = seed;
One way that I allow myself to have access to a variable in different instances is adding it to the process variable. In node.js no matter where in the project it is, it will always be the same. In some cases, I would do process.DB = seed(); which would allow process.DB to always be the result of that. So inside your main class you can do process.DB = seed(); and all of your other classes running off of that one main class would have access to process.DB keeping your database readily available.

Express : router object and methods

I have
var router = express.Router();
router.get('/', function(req, res) {
//something
}
module.exports = router;
Is the router created, the get method executed and the router exported, or is it that the router is created, the method is define for this router (not executed) and the router is exported afterwards?
Second one. Router is created, method is defined and router is exported. That method will be executed when browser sends get request on '/' url, if you correctly require exported router.

Default location of express generator title object

I'm using the express generator to create the framework for a site, which by default includes this line in the layout.jade file:
h1= title
Which calls in the title 'Express' from a local variable (index.jade extends the layout.jade file). However, I can't for the life of me find out where it's getting the variable from.
Can anyone tell me where the express generator creates the file that creates this variable, given I have used the default settings.
Inside the routes directory inside the index.js file
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' }); // <= HERE in the res.render method
});
module.exports = router;
You will find the object, passed as the second argument to the render method, that includes the key value pair {title: 'Express'}

Categories