Express Middleware acting on every router after being added - node.js

I'm having a problem when adding middleware in express.Router().
let router = express.Router();
let mid = function(req, res, next) {
console.log("mid");
next();
}
router.get("/", function(req, res) {
res.send("public");
})
let userRouter = express.Router();
userRouter.use(mid);
userRouter.get("/users", function(req,res) {
res.send("users");
})
router.use(userRouter);
app.use("/", router);
router = express.Router();
router.get("/", function(req, res) {
res.send("api");
})
app.use("/api", router);
and here is the result:
accessing "/" don't triggers the middleware.
accessing "/users" triggers the middleware.
accessing "/api" triggers the middleware.
I don't get why "/api" is triggering the middleware.

Check the Express documentation for router middleware.
The Express API documentation might be useful too.
I organized your code a little bit, and now it is working as you wanted.
'use strict';
let express = require('express');
let expressApp = express();
// --- middleware function ---
let usersMiddleware = function(req, res, next) {
console.log("users router middleware");
next();
}
// --- middleware function ---
let appMiddleware = function(req, res, next) {
console.log("app middleware");
next();
}
// --- public router ---
let publicRouter = express.Router();
publicRouter.get("/", function(req, res) {
res.send("public");
});
// --- user router ---
let userRouter = express.Router();
// --- this is a router based middleware,
// --- to be used only for this router ---
userRouter.use(usersMiddleware);
userRouter.get("/", function(req,res) {
res.send("users");
});
// --- api router ---
let apiRouter = express.Router();
apiRouter.get("/", function(req, res) {
res.send("api");
});
// --- this is a app based middleware,
// --- it will be used for every route of the app after this line
expressApp.use(appMiddleware);
// --- adding the routers to the app ---
expressApp.use("/", publicRouter);
expressApp.use("/users", userRouter);
expressApp.use("/api", apiRouter);
expressApp.listen(8080);
Note that there are two kinds of middleware used here, the one attached to an specific router (that's the one you wanted), and one attached to the app, used for all the further routes (I added this one to show the difference).
/api was triggering the middleware because you added it to the app and not to the router instance.

Related

How to app use all routes from different file

I'm trying to separate my routes, previously i'm including them to my app.js
/backend/app.js
const express = require("express");
const router = require("./routes");
const status = require("./routes/status");
const register = require("./routes/register");
const login = require("./routes/login");
app.use('/', router);
app.use('/status', status);
app.use('/login', login);
app.use('/register', register);
I realized its not ideal since i am adding more and more routes later on and the app.js will be polluted with them
What i want to do now is just to import an index.js to app.js and basically this index have all the routes needed
/backend/routes/index
const routes = require("express").Router();
const root = require("./root");
const status = require("./status");
const register = require("./account/register");
const login = require("./account/login");
routes.use("/", root);
routes.use("/login", login);
routes.use("/register", register);
routes.use("/status", status);
and now in the app.js i can just include the index
const routes = require("./routes");
app.use('/', routes);
but its not working im getting 404 error when trying to request to login route
im exporting them like this
module.exports = routes;
In your app.js
app.use('/', require('./backend/routes/index'))
Then, in your routes/index
import express from 'express'
const router = express.Router()
// GET /
router.get('/', function (req, res) {
})
// GET /countries
router.get('/countries', (req, res, next) => {
})
// POST /subscribe
router.post('/subscribe', checkAuth, generalBodyValidation, (req, res, next) => {
})
// All routes to /admin are being solved in the backend/routes/admin/index file
router.use('/admin', require('./backend/routes/admin/index'))
module.exports = router
Your admin/index file can be
import express from 'express'
const router = express.Router()
// POST /admin/login
router.post('/login', (req, res, next) => {
})
module.exports = router
With this, you will be able to perform a POST request to /admin/login.
Hope this solves your problem, if it does mark my answer as correct, if not tell me what went wrong and I will solve it :D

Nodejs Express router.get('/') in users.js

I m still trying to learn NodeJs but I came across this path thing I encountered in Express. When I create an app using Express I noticed that in app.js I have these lines of code var index = require('./routes/index');
var users = require('./routes/users');
app.use('/', index);
app.use('/users', users);
And in users.js I already have configured
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
I don t really understand why is it in users.js router.get('/') instead of router.get('/users') as it is specified in app.js? Can someone explain a bit what s going on in this case?
As far as I understand in app.js it says whenever someone tries to access the specified route('/users') lets say localhost:3000/users in the browser, let the file required in users variable handle it.
If you are working with routes the express app is automatically . Here is an example from the express.js website:
In our router file we have:
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
Then in our main file were we have our server etc we load in the router:
var birds = require('./birds')
// ...
app.use('/birds', birds)
These routes in the router app are only accessed when there is a request to to /birds url. All the routes in the router are now automatically staring with /birds
So this code in the express router:
// im code in the birds router
router.get('/about', function (req, res) {
res.send('About birds')
})
Is only executed when someone makes a get request to the /birds/about url.
More information in the official express.js docs
I would just like to point out what I have learnt today after some frustration, and maybe somebody can elaborate as to why this happens. Anyway, if, like me, you want to use '/users' for all user routes or '/admin' for all administrator routes then, as WillemvanderVeen mentioned above, you need to add the following code to your main app.js file
var users = require('./routes/users')
app.use('/users', users)
However, one thing which was not mentioned is that the order with which you declare your 'app.use('/users', users)' in app.js is important. For example, you would have two route handling files as so:
/routes/index.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => { res.render('index') });
/routes/users.js
const express = require('express'); const router = express.Router();
router.get('/', (req, res) => { res.send('users route') })
You would then require them in your main app.js file as so:
app.js
const express = require('express');
const app = express();
const index = require('./routes/index');
const users = require('./routes/users');
app.use('/', index);
app.use('/users', users);
and you would expect that when you hit the '/users' route that you would receive the res.send('users route') page.
This did not work for me, and I struggled to find any solution until recently, which is why I am now commenting to help you.
Instead, I swapped the app.use() declarations in app.js around like so and it worked:
app.js
const express = require('express');
const app = express();
const index = require('./routes/index');
const users = require('./routes/users');
app.use('/users', users);
app.use('/', index);
Now when I hit '/users' I see the 'users route' message. Hope this helped.
To answer your question though, when you configure the route handler in app.js as users, then you are requiring a router file (./routes/users) to handle all requests from that file and sending them to the URL /users first. So if you do the following:
/routes/users.js
router.get('/dashboard', (req, res) => {
// get user data based on id and render it
res.render('dashboard')
});
then whenever user is logged in and goes to dashboard, the URL will be /users/dashboard.

expressjs, use regular exp to match route

I use a regular exp to match a path and route the request to pageRouter.
When I request the localhost:8000/new, the regular EXP looks not work, but I have test the EXP use /^\/(?!api$|api\/.*|resource$|resource\/.*)/.test('/new'), it return true.
What happened?
router.use('/api',apiRouter);
router.use('/resource',resourceRouter);
router.use(/^\/(?!api$|api\/.*|resource$|resource\/.*)/,pageRouter);
pageRouter.get("*",(req,resp,next)=>{let name = req.originalUrl...})
In this case, instead of regexp you just need to use the wildcard :
const express = require('express'); const app = express()
app.get('/api', function(req, res){ res.send('API·Router') })
app.get('/resource', function(req, res){ res.send('RESOURCE·Router') })
app.get('/*', function(req, res){ res.send('[*] PAGE.Router') })
app.listen(3000)
Its important to define all the other routes before the wildcard '/*'
WHY? : If your first route is the wildcard, it will trap all the requests
Detecting Paths using Wildcard
app.get('/*', function (req, res) {
var paths = req.path.split("/")
if(paths[1].length==0){
res.send('[/] Page.Root')
}else if(paths[1]=='portal'){
if(paths[2]){ res.send('[*] PAGE.Router : '+paths[2]) }
else{ res.send('[*] PAGE.Router : '+paths[1]) }
}else{ res.send('[404] PATH : '+paths[1]+' not found!') }
});
Using an array :
If you have a specific list of routes that you want to use for pageRouter you can always group them inside an array for the first argument of the app.get() handler :
const pageRoutes = ['en/page','es/pagina','dk/side','jp/頁']
app.get(pageRoutes, function(req, res){ res.send('[*] PAGE.Router') })
It seems OP is trying to exclude /api and /resource for pageRouter by regular expression. However, it's not needed. As long as /api and /resource router are defined before pageRouter, they will be triggered first, and won't go though pageRouter any more.
Just define /api and /resource before pageRouter, and then use router.use('/', pageRouter);, so that all URL except /api and /resource will be listened by pageRouter.
Here is the example code. I've verified and confirmed that HTTP request to /resource won't go through pageRouter.
Files:
./app.js
./routes.js
./pageRouter.js
./resourceRouter.js
For ./app.js:
const express = require('express');
const app = express();
const routes = require('./routes');
app.use('/', routes);
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
});
For ./routes.js:
var express = require('express');
var router = express.Router();
const resourceRouter = require('./resourceRouter');
const pageRouter = require('./pageRouter');
router.use('/resource',resourceRouter);
router.use('/', pageRouter);
module.exports = router;
For ./resourceRouter.js:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send('respond with resource');
});
module.exports = router;
For ./pageRouter.js:
var express = require('express');
var router = express.Router();
router.get('/resource', function(req, res, next) {
console.log('hit /resource in pageRouter');
res.send('respond with page by /resource');
});
router.get('/new-page', function(req, res, next) {
res.send('respond with page by /new-page');
});
router.get('*', function(req, res, next) {
console.log('hit * in pageRouter');
res.send('respond with page by *');
});
module.exports = router;
After running ./app.js, the HTTP GET request for /resource would never hit ./pageRouter.js.
I got an answer from the expressjs's github,the link is https://github.com/expressjs/express/issues/3404
It is not just a matter of does the regular expression match the
input, but since .use needs to strip down the matched path, it expects
your match to stop before a / character to cut on.

Express ip filter for specific routes?

Is it possible to apply different ip filters to different routes?
For example, I want only people from 123.123.123.123 can access my server's /test route, and only people from 124.124.124.124 can access my server's / route.
I know that express-ipfilter can restrict site access by IP Address. But it cannot apply the filter to specific routes.
I also know that adding app.use(ipfilter(ips, {})); in the middle of the routes can apply filter only to the routes below:
var express = require('express'),
ipfilter = require('express-ipfilter').IpFilter;
var ips = ['::ffff:127.0.0.1'];
var app = express();
app.get('/test', function(req, res) {
res.send('test');
});
app.use(ipfilter(ips, {})); // the ipfilter only applies to the routes below
app.get('/', function(req, res) {
res.send('Hello World');
});
app.listen(3000);
But I want different filters for different routes.
Is it possible to do this?
Yeah, it's possible. You could do something like:
app.get('/test', function(req, res){
var trustedIps = ['123.123.123.123'];
var requestIP = req.connection.remoteAddress;
if(trustedIps.indexOf(requestIP) >= 0) {
// do stuff
} else {
// handle unallowed ip
}
})
You may need to make sure that requestIP is correctly formatted though.
Warning: package express-ipfilter is now deprecated.
You can chain middlewares (and ipFilter is a middleware). There are 2 ways to do this:
var express = require('express'),
ipfilter = require('express-ipfilter').IpFilter;
var ips = ['::ffff:127.0.0.1'];
var testers = ['1.2.3.4'];
var app = express();
app.get('/test', ipfilter(testers, {mode: 'allow'}), function(req, res) {
res.send('test');
});
// the ipfilter only applies to the routes below
app.get('/', ipfilter(ips, {mode: 'allow'}), function(req, res) {
res.send('Hello World');
});
app.listen(3000);
Or qualify the use of the middleware:
var express = require('express'),
ipfilter = require('express-ipfilter').IpFilter;
var ips = ['::ffff:127.0.0.1'];
var testers = ['1.2.3.4'];
var app = express();
app.use('/test', ipfilter(testers, {})); // the ipfilter only applies to the routes below
app.get('/test', function(req, res) {
res.send('test');
});
app.use('/', ipfilter(ips, {})); // the ipfilter only applies to the routes below
app.get('/', function(req, res) {
res.send('Hello World');
});
app.listen(3000);
In your main file where u defined app,
app.use('/test',require('./whereever-my-route-is-located-where /test routes '));
app.use('/',require('./wherever-my-this-routes-are-located'))
in your route file .
var express = require('express'),
router = express.Router();
//Ip verification for all requests : for whereever-my-route-is-located-where /test routes
router.use(function(req, res, next) {
//verify Ip Logic
});
//this will be called for every route u define in that file, if it fails.

How to use multiple router files

How do I use multiple router files using express framework?
In my app.js, I have the following code:
var controller = require('./controller/index');
var healthController = require('./controller/health/');
app.use('/', controller);
app.use('/health', healthController);
And controller/index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
And health.js:
var express = require('express');
var router = express.Router();
/* GET health confirmation. */
router.get('/health', function(req, res, next) {
res.send('OK');
});
module.exports = router;
When I hit the http://localhost:8000/, I get the correct page without any problem, however, http://localhost:8000/health results in 404 error.
Thanks in advance.
Assuming the "health.js" resides in "controller" directory, may it be just a typo issue? var healthController = require('./controller/health/'); has a trailing slash (/). Removing it would fly? So it becomes var healthController = require('./controller/health');
Your single node app must have single router object, a router object represents a server in express requiring unique port.
Hence you should create router object in you app.js passing it to all router files.
Code will be like -
app.js
var express = require('express');
var router = express.Router();
var controller = require('./controller/index');
var healthController = require('./controller/health/');
controller(router);
healthController(router);
index.js
module.exports = function(router) {
router.get('/', function(req, res, next) {
res.render('index');
});
}
health.js
module.exports = funtion(router) {
router.get('/health', function(req, res, next) {
res.send('OK');
});
}
See How to include route handlers in multiple files in Express?.
Export an anonymous function that can be "initiated" with a reference to the original express app.
./controller/index.js:
module.exports = function(app) {
/* GET home page. */
app.get('/', function(req, res, next) {
res.render('index');
});
};
./controller/health.js:
module.exports = function(app) {
/* GET health confirmation. */
app.get('/health', function(req, res, next) {
res.send('OK');
});
};
./app.js:
var app = require('express')();
var controller = require('./controller/index');
var healthController = require('./controller/health');
controller(app);
healthController(app);
Change in health.js:
router.get('/health', function(req, res, next) {
res.send('`OK`');
});
to
router.get('/', function(req, res, next) {
res.send('OK');
});
This will work fine check it out.

Resources