So on router level file, I need to protect almost all routes with at least one middleware, except for one route. So far I tried something like this:
// comments.js
const express = require('express');
const router = express.Router({ mergeParams: true });
const m = require('../middlewares');
// /api/:newsId/comments - preappended route
router.use((req, res, next) => {
if(req.path == '/' && req.method == 'GET') return next(); // doesn't work, even with next('route')
if(m.isLoggedIn) { // this doesn't work either
next();
}
})
router.get('/', (req, res) => {
// returns comments for :newsId, only this route doesn't need middlewares
})
// all below routes needs at least m.isLoggedIn
router.post('/', (req, res) => {
// creates a new comment
})
// ...
// bunch of other routes which needs middleware m.isLoggedIn and maybe some others
module.exports = router;
I know I can append middlewares on each route, but I am looking for better solution to use in router.use().
Related
For my NodeJs project I use the Express router. I created a router.js
module.exports = (app) => {
app.use('/', require('./routes/home.js'));
app.use('/contact', require('./routes/contact.js'));
app.use('/imprint', require('./routes/imprint.js'));
};
and in my app.js I require this file require('./server/router.js')(app);. When calling a route, for example /contact I require the contact.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
res.render('contact', { // render contact.hbs
title: 'Contact' // pass in some template variables
});
});
module.exports = router;
Within router.get I can use console.log(req.method) to log the HTTP method. Currently I would have to log this in all router files. Is it possible to have the code at one place like
module.exports = (app) => {
console.log(req.method); // Log the request method for all routes
app.use('/', require('./routes/home.js'));
app.use('/contact', require('./routes/contact.js'));
app.use('/imprint', require('./routes/imprint.js'));
};
Please provide a solution without installing middleware. I know there are many loggers out there.
If you want to avoid installing middleware and use console.log you can change your code as follows:
module.exports = (app) => {
app.use((req, res, next) => {
console.log('Request Type:', req.method);
console.log('Time:', Date.now());
next();
})
app.use('/', require('./routes/home.js'));
app.use('/contact', require('./routes/contact.js'));
app.use('/imprint', require('./routes/imprint.js'));
};
If you don't specify a route but have the next callback in, then it will execute your logging code first then the matching routing if there is one. You can find more details in the using middleware section of the ExpressJS API documentation.
What I want to do
if req is from mobile
first check these routes
router.use('/', mobileRoutes);
then ones below
router.use('/', routes);
but as far as I understand express goes through all use statements upon every request, it runs them all once and put route handlers into some sort of array. that get hit with requests.
For some urls I want to server different pages but no all (loginPage, registrationPage, etc).
Is it possible to do conditional routing, to prepend more routes in case some condition is met.
What I do have working is this:
router.use(function (req, res, next) {
let md = new MobileDetect(req.headers["user-agent"]);
if (md.mobile()) {
req.url = '/mobile'+req.url;
}
next();
});
//mobile routes
router.use("/mobile", require("./mobile"));
but it completely blocks all routes below.
I want a clean solution, One another option, which is not clean, is to add middleware to individual routes but that muddies code endlessly.
My Solution for conditional routing:
index.js
.....
//mobile routes
router.use("/", require("./mobile"));
router.get("/", require("./get"));
.....
mobile.js
const express = require("express");
const router = express.Router();
const MobileDetect = require("mobile-detect");
router.use(function (req, res, next) {
let md = new MobileDetect(req.headers["user-agent"]);
(md.mobile())? next() : next("router")
});
router.get("/", function (req, res) {
res.send({ query: req.query });
});
module.exports = router;
I would like to protect some endpoints in my express app, I want to create something simple to manage if my app became a big app...now I'm doing something like this:
setProtected(router) {
const self = this;
router.use(this.auth);
...
}
setPublic(router) {
const self = this;
...
}
getRouter() {
const router = express.Router();
this.setPublic(router);
this.setProtected(router);
return router;
}
with:
auth(req, res, next) {
if(req.isAuthenticated()) {
console.log('req.isAuthenticated()', req.isAuthenticated());
return next();
}
return res.send(401);
}
the problem in this case is that is difficult maintain and it doesn't work well as if I have /:id in my publicRoute and for example /my-items in my protected route when I'm not logged and I try to reach /my-items I get the code of /:id.
Another idea was to create a json with the list of all my urls with same information like protected/not protected and eventual roles and then change auth with something like:
import urls from './urls';
auth(req, res, next) {
if (urls[req.url] == 'public') {
return next()
}
else if (urls[req.url] == 'protected' && req.isAuthenticated()) {
return next();
}
return res.send(401);
}
whats the best way for you?
You can chain middlewares:
eg.
const authenticate = (req, res, next) {
.. some auth logic
next();
}
app.use('/', main...
app.use('/profile', authenticate, otherMiddleware,
app.use('/admin', authenticate, isAdmin, otherMiddleware...
in your main file (server.js) import the routes and use the middleware there :)
server.js
const express = require('express')
const cors = require('cors')
const app = express()
// import admin routes
const adminRoute = require('./app/routes/admin.route.js')
// Add middleware for parsing URL encoded bodies (which are usually sent by browser)
app.use(cors())
// Add middleware for parsing JSON and urlencoded data and populating `req.body`
app.use(express.urlencoded({ extended: false }))
app.use(express.json())
// homepage route
app.get("/", (req, res) => {
res.json({ message: "Hello World" })
})
// restricted by middleware "isAdmin"
app.use('/api/v1', isAdmin, adminRoute)
app.listen(8008).on('listening', () => {
console.log('Server is running on 8008')
})
admin.route.js
const express = require('express')
const admin = require('../controllers/admin.controller.js')
const router = express.Router()
// get all admin users
router.get('/users', (req, res, next) => {
admin.getAdminUsers(req, res, next)
})
module.exports = router
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)
});
}
I want to just verify something but have't been able to find anything in the Express docs or online regarding this (although I know it's a feature).
I could just test this out but I don't really have a nice template and would like to hear from the community.
If I define a route in express like such:
app.get('/', function (req, res) {
res.send('GET request to homepage');
});
I can also define a middleware and load it directly, such as
middleware = function(req, res){
res.send('GET request to homepage');
});
app.get('/', middleware)
However, I can also chain at least one of these routes to run extra middleware, such as authentication, as such:
app.get('/', middleware, function (req, res) {
res.send('GET request to homepage');
});
Are these infinitely chainable? Could I stick 10 middleware functions on a given route if I wanted to? I want to see the parameters that app.get can accept but like mentioned I can't find it in the docs.
Consider following example:
const middleware = {
requireAuthentication: function(req, res, next) {
console.log('private route list!');
next();
},
logger: function(req, res, next) {
console.log('Original request hit : '+req.originalUrl);
next();
}
}
Now you can add multiple middleware using the following code:
app.get('/', [middleware.requireAuthentication, middleware.logger], function(req, res) {
res.send('Hello!');
});
So, from the above piece of code, you can see that requireAuthentication and logger are two different middlewares added.
It's not saying "infinitely", but it does say that you can add multiple middleware functions (called "callbacks" in the documentation) here:
router.METHOD(path, [callback, ...] callback)
...
You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to perform pre-conditions on a route then pass control to subsequent routes when there is no reason to proceed with the route matched.
As you can see, there's not distinction between a middleware function and the function that commonly handles the request (the one which is usually the last function added to the list).
Having 10 shouldn't be a problem (if you really need to).
Express version "express": "^4.17.1" or above
From the document: Series of Middleware
var r1 = express.Router();
r1.get('/', function (req, res, next) {
next();
});
var r2 = express.Router();
r2.get('/', function (req, res, next) {
next();
});
app.use(r1, r2);
Let's try a real life example:
tourController.js
exports.checkBody = (req, res, next)=>{ // middleware 1
if (!req.body.price){
return res.status(400).json({
status:'fail',
message:'Missing price!!!'
})
}
next();
}
exports.createTour = (req, res) => { // middleware 2
tours.push(req.body);
fs.writeFile(
`${__dirname}/dev-data/data/tours-simple.json`,
JSON.stringify(tours),
(err) => {
res.status(201).json({
status: 'success',
data: {
tour: newTour,
},
});
}
);
};
tourRouter.js
const express = require('express');
const tourController = require('./../controller/tourController')
const router = express.Router();
router.route('/')
.get(tourController.getAllTours)
.post(tourController.checkBody, tourController.createTour);
//muliple Middleware in post route
module.exports = router //need this or the following step will break
app.js
const express = require('express');
const tourRouter = require('./route/tourRouter');
const app = express();
app.use(express.json());
app.use('/api/v1/tours', tourRouter);
module.exports = app;