How to use nested middleware in express.js - javascript

I want to make a change from the actual structure of my code. This is the actual code i have:
//index.js
var routes = require('./routes');
var subdomain = require('express-subdomain');
//require express app with settings
var app = require('./app');
//export the application
module.exports = app;
// routes request like endusers-api.mydomain.ext/
app.use(subdomain('endusers-api', routes.apis.endusers));
// routes request like mydomain.ext/
app.use(routes.webapps.endusers);
//routes/index.js
var apis = {endusers: require("./apis/endusers")}
var webapps = {endusers: require("./webapps/endusers")}
var routes = {apis: apis, webapps: webapps}
module.exports = routes;
//routes/apis/endusers
var express = require('express');
var route = express.Router();
var logger = require('../../lib/logger');
route.get('/', logger("endusers-api-access"), function(req, res, next) {
res.json({
"name" : "Endusers API"
});
});
module.exports = route;
//routes/webapps/endusers.js
var express = require('express');
var route = express.Router();
var logger = require('../../lib/logger');
route.get('/', logger("endusers-webapp-access"), function(req, res, next) {
res.render('endusers/index', {title: 'Homepage'});
});
module.exports = route;
Now I want to change the above code to this (feel free to tell me if this is a good approach of doing things in Node.js or not):
//index.js
var middlewares = require('./middlewares');
var app = require('./app');
module.exports = app;
//i want to change to this
app.use(middlewares.endusersApi);
app.use(middlewares.endusersWebapp);
//Stuff for creating server and listening...
//middlewares/index.js
var middlewares = {
endusersApi : require("./apis/endusers"),
endusersWebapp : require("./webapps/endusers")
}
module.exports = middlewares;
//middlewares/apis/endusers.js
//TODO
//middlewares/webapps/endusers
//TODO
How should I write the TODO portions above. It look like we will need nested middlewares (a middleware calling another middleware). Please, your suggestions.

I found the answer using by express.Router().all() method.
//middlewares/apis/endusers.js
var routes = require('../../routes');
var express = require('express');
var middleware = express.Router();
middleware.all('/',subdomain('endusers-api', routes.apis.endusers));
//the two next lines are alternatives to the line above
//middleware = subdomain('endusers-api', routes.apis.endusers); //can assign only one route
//middleware.use(subdomain('endusers-api', routes.apis.endusers)); // can use many routes
module.exports = middleware;
//middlewares/webapps/endusers.js
var routes = require('../../routes');
var express = require('express');
var middleware = express.Router();
middleware.all('/', routes.webapps.endusers);
//the two next lines are alternatives to the line above
//middleware = routes.webapps.endusers; //can assign only one route
//middleware.use(routes.webapps.endusers); // can use many routes
module.exports = middleware;

Related

Why is my route not being hit?

Hi I have an express router that seems to not get hit when I navigate to the proper route. In my app.js:
var auth = require('./routes/auth');
app.use('/auth', auth);
In my routes/auth.js
var express = require('express');
var authRouter = express.Router();
var mongodb = require('mongodb').MongoClient;
var router = function(){
authRouter.route('/signUp')
.post(function (req, res){
console.log("Hello world");
});
return authRouter;
};
module.exports = router;
In my index.jade:
form.login-form(role='form', action='/auth/signUp', method='post', name='signUpForm' )
.form-group
label.sr-only(for='form-username') Username
input#form-username.form-username.form-control(type='text', name='userName', placeholder='Email...')
.form-group
label.sr-only(for='form-password') Password
input#form-password.form-password.form-control(type='password', name='password', placeholder='Password...')
button.btn(type='submit') Sign up!
However when I try to go to /auth/signUp all I get in terminal is: GET /auth/signUp - - ms - -
POST /auth/signUp - - ms - -
It seems to me that my auth/signUp is never hit. I was originally trying to console.log my req.body however I cannot even log a hello world.
You're wrapping your router in a function which is never called. Try just doing this instead:
var express = require('express');
var authRouter = express.Router();
var mongodb = require('mongodb').MongoClient;
authRouter.route('/signUp').post(function (req, res){
console.log("Hello world");
});
module.exports = authRouter;
first, you shouldn't really use cased urls like signUp. Try this:
var express = require('express');
var authRouter = express.Router();
var mongodb = require('mongodb').MongoClient;
var router = function(){
authRouter.post('/sign-up', function (req, res) {
console.log("Hello world");
});
return authRouter;
};
module.exports = router;
You are using wrong way of defining routers. Use this way instead.
var express = require('express');
var authRouter = express.Router();
authRouter.post('signUp', function(req, res) {
// in this code block you have to render text, html or object
res.render('index'); // or may be res.json(some_obj);
})

Add Routes at Runtime (ExpressJs)

I would like to add routes at run time. I read that its possible but I am not so sure how. Currently I using the following code:
var app = express();
function CreateRoute(route){
app.use(route, require('./routes/customchat.js'));
}
And customchat looks like
var express = require('express');
var router = express.Router();
router.route('/').get(function (req, res) {
var url = req.baseUrl;
var roomname = url.substring(url.lastIndexOf('_') + 1);
res.render('chat', { name: roomname , year: new Date().getFullYear().toString()});
});
module.exports = router;
When I call the method CreateRoute before I start listening it will link the route. But when I do it at runtime it wont create a new route.
My goal is to add routes add runtime. I will generate an path like /room_Date. And this should be added at runtime using the template customchat.
I am using express version 4.13.
Thanks in advance for your help.
customchat.js should called customChat.js and be
const customChat = (req, res) => {
const { name } = req.params;
const year = new Date().getFullYear().toString();
res.render('chat', { name , year });
}
module.exports = customChat
then when you create your app
const express = require('express')
const customChat = require('./routes/customChat.js')
const app = express()
app.use('/chat/:name', customChat)
See the official Express routing docs for more information.

Cannot figure out how to render a new page in express

I have this ships.js in my routes folder:
var express = require('express');
var router = express.Router();
/* GET Ships page. */
router.get('/ships', function(req, res, next) {
res.render('ships', { title: 'Express' });
});
module.exports = router;
And I have these to statements in my app.js:
var routes = require('./routes/index');
var users = require('./routes/users');
var ships = require('./routes/users');
and
app.use('/', routes);
app.use('/ships', ships);
app.use('/users', users);
However if I navigate to localhost:3000/ships I receive the following message:
respond with a resource
Sorry have read the docs, just not to snazzy with express.
You have two errors in you app module:
1.Invalid require call for ships route:
var ships = require('./routes/users'); <--
// should be:
var ships = require('./routes/ships');
2.Invalid router using in app.use:
app.use('/ships', ships);
// should be:
app.use(ships); // and the same for others

externalizing route.param() calls in Express.js

I want to extract some repetitive code into a single module in Node.js and Express.js
Together.js
var express = require('express');
var boom = require('express-boom');
var app = express();
var app.use(boom());
app.param('user', function(request, reply, next, id){
request.db.users.get(id, function(err, userInfo){
if (err) reply.boom.badImplementation(err);
else if (!userInfo || !userInfo.length) reply.boom.notFound();
else {
request.user = userInfo[0];
next();
}
})
})
app.get('/api/users/:user', function(request, reply){
reply.json(request.user);
});
app.listen(3000);
I have multiple routes I want to use this param conversion including: /users/:user, /api/users/:user, /checkout/:user/:barcode, etc. but each of the root routes (i.e. users, api, checkout) are in their own file and I am attaching them with app.use('/users', userRoutes);. As it is, I will have to put my user param conversion into EACH of these sub-route modules.
I would like to have an interceptors.js where I make all of the common param interceptor functions and only write them once. Here is an example of how I thought it would work.
app.js
var express = require('express');
var app = express();
app.use(require('./routes/interceptors'))
app.use('/users', require('./routes/users'));
app.use('/api', require('./routes/api'));
app.use('/checkouts', require('./routes/checkouts'));
app.listen(3000);
./routes/api.js
var express = require('express');
var api = express.Router();
api.get('/users/:user', function(request, reply){
reply.json(request.user);
});
module.exports = api;
./routes/interceptors.js
var express = require('express');
var boom = require('express-boom');
var interceptors = express.Router();
var interceptors.use(boom());
interceptors.param('user', function(request, reply, next, id){
request.db.users.get(id, function(err, userInfo){
if (err) reply.boom.badImplementation(err);
else if (!userInfo || !userInfo.length) reply.boom.notFound();
else {
request.user = userInfo[0];
next();
}
})
})
module.exports = interceptors;
There would of course be another file for each of checkout.js and users.js and they will be the same principal as api.js
When I do the above, the param interceptor is never run. No errors are throw that I can see.
Thank you all for any help you may provide,
Rhett Lowe
This can't be done.
Param callback functions are local to the router on which they are defined. They are not inherited by mounted apps or routers. Hence, param callbacks defined on app will be trigerred only by route parameters defined on app routes.
http://expressjs.com/api.html#app.param
Another approach you could do is to have a module with your interceptors and require it in your route files where necessary.
./routes/api.js
var express = require('express');
var api = express.Router();
var interceptors = require('./interceptors');
api.use('user', interceptors.user);
api.get('/users/:user', function(request, reply){
reply.json(request.user);
});
module.exports = api;
./routes/interceptors.js
exports.user = function(request, reply, next, id){
request.db.users.get(id, function(err, userInfo){
if (err) reply.boom.badImplementation(err);
else if (!userInfo || !userInfo.length) reply.boom.notFound();
else {
request.user = userInfo[0];
next();
}
})
})
module.exports = interceptors;

Unable to Split Routes into Separate Files in Express 4.0

I'm trying to redirect all my routes ending with /api to a manager.js which will then route it to /me.
So, a fully qualified request to /me should look like /api/me. Splitting routes up into separate files was easy in Express 3.x, but I'm having trouble in 4.0.
app.js
app.use('/api',require('./routes/manager'));
manager.js
var express = require('express');
var manager = express.Router();
module.exports = function() {
manager.use('/me',require('../routes/me'));
};
me.js
var express = require('express');
var me = express.Router();
module.exports = function() {
me.route('/')
.get(function(req,res){
res.send("Welcome to Me");
});
};
When I go to localhost:8080/api/me, nothing happens, the page keeps loading.
Thanks for any help!
You are not quite properly passing through the Router objects. Keep in mind that this is what you are trying to do:
app.use('/api', express.Router());
but what you are effectively doing right now is this:
app.use('/api', function(){
express.Router()
});
So you instead of exporting a function, you should be exporting the Router itself.
manager.js
var express = require('express');
var manager = express.Router();
manager.use('/me',require('../routes/me'));
module.exports = manager;
me.js
var express = require('express');
var me = express.Router();
me.route('/').get(function(req,res){
res.send("Welcome to Me");
});
module.exports = me;

Categories