Access Express app within Express Router - javascript

I have an ExpressJS application that uses several routers. Here is the basic form of the main app that ties everything together.
var express = require('express');
var routes = require('./routes/index');
var app = express();
app.set('someKey', someObj);
app.use('/', routes);
module.exports = app;
I have removed most of the code for brevity.
In that ./routes/index.js file I have defined a Express Router in the form:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.render('index', { title: 'Express Test' });
});
module.exports = router;
I have attempted to use the following to access "somekey" from inside the router:
var app = require('../app');
var foo = app.get('somekey');
This crashes and burns with the runtime informing me that there is no such method get for app (further investigation yields that app is just a default Object).
I assume I am overlooking something that is completely obvious.
I plan to be passing a single knexjs object to each of the routers that deal with database calls. In the code's current state it is duplicated across each of the routers. I'd like to have it defined once in the main app and then be used by all of the routers such that if a change is made in the main app it is reflected across the routers.

When you require the app that way, you are not exactly referring to the app object you defined in your app.js. Instead, you are asking for whatever that file exported. To get what you want to achieve, may use something like this.
In your app.js
var express = require('express');
var app = express(); // Note the switched order
app.set('someKey', someObj);
var routes = require('./routes/index')(app);
app.use('/', routes);
module.exports = app;
Then in your routes:
var express = require('express');
var router = express.Router();
/* Wrap everything inside a function */
module.exports = function(app){
console.log(app.get('someKey')); // Access app passed to it from app.js
/* Declare all your routes here. app variable will be accessible */
router.get('/', function(req, res) {
res.render('index', { title: 'Express Test' });
});
return router;
};
Basically, whenever you are requiring a file B from A and want to pass a variable from A to B, this is the general pattern you follow.
See if if helps. :)

Related

Appending a Prefix to Routes in One File in Express JS

I am currently refactoring my code and I am hoping there is a more efficient way to make my code look pretty. Here is what I currently have:
router.route('/api/merchant/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/api/user/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/admin/user/')
.get(controllerFunction)
.post(controllerFunction);
router.route('/admin/place/')
.get(controllerFunction)
.post(controllerFunction);
You can see that I have "api" and "admin" as prefixes to certain routes.
I can separate the API route into another file and have the "app.use" middleware append them appropriately, but I was wondering how can I get around this and have these routes in a single file with the main problem being at the end of the file:
module.exports = router
which only allows me to have one prefix to all my routes.
Short answer for your question follow below
You can put your middleware in separate file.
[name]Controller.js
module.exports = (req, res)=>{
res.send('I am a middleware');
}
Create a file bootable routers and export an array from routers.
boot.js
const express = require('express'),
router = express.Router(),
[name]Controller = require('./controller/[name]Controller'),
module.exports = [
router.get('/your path', [name]Controller),
...
]
Use router in your app file.
app.js
const express = require('express'),
boot = require('./boot'),
app = express();
app.use('/prefix', boot);
Now you can use routes with prefix for example:
localhost:3000/prefix/yourpath
You can folow below block code, but I suggest you write controler function to another file each for once.
var router = express.Router();
var useApi = router.route('/user')
.get(controllerFunction)
.post(controllerFunction);
var useAdmin = router.route('/user')
.get(controllerFunction)
.post(controllerFunction);
app.use('/api', userApi);
app.use('/admin', userAdmin);
You can mount the whole router on a path. If you do something like:
router.get('/:id', someFn);
Then elsewhere you could do:
app.use('/api', router);
and the route '/api/:id/` would resolve to the someFn handler
UPDATE
I'm not sure I fully understand your concern, and frankly having all your routes in one file makes for a file longer than I'm comfortable with, but if you really only want to mount one router, you can do something similar to what I described, but inside your routes file.
In that case, you'd still create the multiple routers but then rather than exporting them and mounting on the app, you'd do this:
const adminRouter = express.Router();
// configure the admin routes as I described
const apiRouter = express.Router();
// configure API routes
const main = express.Router();
main.use('/admin', adminRouter);
main.use('/api', apiRouter);
module.exports = main;

Taking routes from server.js to routes.js without passing parameters

I have a server.js on my root folder with the following content.
// server.js
const app = express();
const HomeController = require("./controllers/HomeController");
const UserController = require("./controllers/UserController");
app.use(...)
app.use(...)
app.get('/', HomeController.index);
app.get('/login', UserController.getLogin);
I want to take app.get endpoints in a file called routes.js so it looks like this:
// routes.js
app.get('/', HomeController.index);
app.get('/login', UserController.getLogin);
When I do it, app, HomeController and UserController becomes undefined.
I can pass them to routes.js like so:
require("routes")(app, HomeController, UserController);
However, it is not future compatible so if I ever create a new controller, I must pass them into routes.js file.
Instead, can I somehow tell routes.js to access server.js scope? Is there any way to access variables in server.js via routes.js?
Why you didn't use the default pattern of the ExpressJS. like:
var apiRoutes = require('./api_server/routes/api');
app.use('/api', apiRoutes);
.../routes/api.js:
var express = require('express');
var router = express.Router();
var loginCtrl = require('../controllers/auth/login');
router.post('/authenticate', loginCtrl.login);
router.post('/resetAdminPassword', loginCtrl.resetAdmin);
// router.get('/tieba/:id', tiebaCtrl.one);
module.exports = router;

Pass array to routes/index.js from app.js in Nodejs with Express 4

How can I pass an array of objects to the routes middle-ware so that I can render the view depending on the variables passed.
Currently, this is the layout I am working with
app.js
var index = require('./routes/index');
ARRAY = [objects];
app.use('/', index);
routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next){
res.render('index', {data: ARRAY});
});
module.exports = router;
index.jade
extends layout
block content
each d in data
div!= d.method()
Currently the only solution I can produce that actually works is to use global variables, but this is not sustainable or scalable.
I have tried app.set('shrinkr', shrinkr); and app.locals but cannot get either of these to work with the layout of my app. From my understanding of the Express4 framework I should be able to do something like this in app.js:
var index = require('./routes/index')(array);
but I cannot get the implementation correct, and there is no info about this on the web.
There are multiple ways that you can tackle this, but if you want to "bake" the array into the middleware (as your code sample suggested), you can do this:
var express = require('express');
module.exports = function(array) {
var router = express.Router();
return router.get('/', function(req, res, next){
res.render('index', {data: array});
});
}
Then you can use it as you suggested:
var index = require('./routes/index')(array);
Because new middleware is created every time you invoke the exported function, you can bake independent arrays into different middleware:
var index1 = require('./routes/index')(["array 1"]);
var index2 = require('./routes/index')(["array 2"]);
Which may or may not be useful to you, depending on your needs.

Get access to Express mountpath from inside a module

In an attempt to build a truly modular express app (one that can run stand alone or as a part of another app) I need to find out the cleanest way to find the mount path from inside the subapp. For a short example, lets say that there are two files: main.js and subapp.js
main.js
var express = require('express');
var app = express();
var localApp = express();
var subapp = require('./subapp');
app.use('/foo', subapp);
app.use('/bar', localApp);
console.log(localApp.mountpath); // yes, this prints '/bar' as expected
...
subapp.js
var express = require('express');
var app = express();
var truePath = app.mountpath; // I wish this would point to '/foo', but instead points to '/'
...
module.exports = app;
What is the best way (as in cleanest) to find the mountpath from inside the module? I'm doing this trying to solve this problem: Access to mountpath variable from inside a template using express in a non hardwired way.
As shown in the example, tried already with app.mountpath without success
As answered by alsotang, this is actually a problem of execution sequence, but it can be solved in what I think is a clean way. There is an event that is fired after the module is mounted, so you can do:
var truePath = = "/";
app.on('mount', function (parent) {
truePath = app.mountpath;
});
Where in real life truePath could be app.locals.truePath, so it can be accessed from inside the views.
eh..It's a problem of execution sequence.
In your subapp.js, the app.mountpath statement is before module.exports = app.
But only you export the app, then the app be mounted, then it would be set the mountpath property.
so, you should retrieve mountpath after the app be mounted by outer express.
My suggestion are two:
set the mountpath in your subapp.js. And outer express read this property.
perhaps you think 1 is not truly modular. so you can alternatively define a config file. and both main.js and subapp.js read mountpath from the config.
Try req.baseUrl:
app.js
var express = require('express');
var app = express();
var foo = require('./foo');
app.use('/foo', foo);
app.listen(3000);
foo.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
console.log(req.baseUrl); // '/foo'
res.send('foo');
});
module.exports = router;

ExpressJS require

I was reading over the Express.JS 4.x API and was curious about how they set this up. Here's my understanding of what is happening:
In this sample code in the Express.JS 4.x API, the express module is imported and assigned to a variable express. That variable is then used to call the express constructor and is assigned to the variable app.
var express = require('express');
var app = express();
app.get('/', function(req, res){
res.send('hello world');
});
app.listen(3000);
Is there a difference if the express module is directly assigned to app or is the assignment above just for readability? As follows:
var app = require('express')();
A node module can return a constructor that is both a constructor AND also has properties (since functions are objects that can have properties).
Your first method allows you to access any other properties or methods that the constructor might have. The second method does not permit that since it doesn't retain a reference to the constructor.
In the ExpressJS documentation, I do see some items that are referenced via the express object such as:
var express = require('express');
var app = express();
var router = express.Router();
router.get('/', function (req, res, next) {
next();
});
app.use(router);
and
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
If you don't need to retain a reference to the constructor in order to access these other methods on it, then there is no difference between your two options as they execute the same code. Your second one just doesn't retain a reference to an intermediate step that can be used later to access other things.

Categories

Resources