Express.js conditional router.all() - node.js

I don't understand why urls starting with 2016 don't work. It just loads forever.
main (/), admin (/admin/*) and /home work without an issue.
function stringStartsWith(string, prefix) {
return string.slice(0, prefix.length) == prefix;
}
router.get('/', csrfProtection, indexOnly, indexController.index);
router.get('/admin', adminOnly, adminController.index);
router.all('/*', function(req, res, next) {
if (req.originalUrl == '/home') {
next();
} else if (stringStartsWith(req.originalUrl, "/admin")) {
router.all('/admin/*', function(req, res, next) {
if (req.originalUrl == '/admin') {
next(); // it doesn't do anything, just allows the route above to work (admin welcome page.)
} else {
res.sendFile(path.resolve('views/backend/index.html'));
}
});
} else if (stringStartsWith(req.originalUrl, "/2016")) {
router.all('/2016/*', function(req, res, next) {
res.sendFile(path.resolve('views/frontend/index/index.html'));
});
} else {
res.sendFile(path.resolve('views/frontend/index.html'));
}
});

why do you put the 2016 route inside other route? it should simply be another route like the others:
function stringStartsWith(string, prefix) {
return string.slice(0, prefix.length) == prefix;
}
router.get('/', csrfProtection, indexOnly, indexController.index);
router.get('/admin', adminOnly, adminController.index);
router.all('/2016/*', function(req, res, next) {
res.sendFile(path.resolve('views/frontend/index/index.html'));
});
router.all('/*', function(req, res, next) {
if (req.originalUrl == '/home') {
next();
} else if (stringStartsWith(req.originalUrl, "/admin")) {
router.all('/admin/*', function(req, res, next) {
if (req.originalUrl == '/admin') {
next(); // it doesn't do anything, just allows the route above to work (admin welcome page.)
} else {
res.sendFile(path.resolve('views/backend/index.html'));
}
});
} else {
res.sendFile(path.resolve('views/frontend/index.html'));
}
});

Related

how to properly inject middleware in NodeJS route

How can i inject my middleware function 'checkAuthenticated' into my get route below?
not sure how to properly inject the code below. Please let me know. thank you very much.
function checkAuthenticated(req, res, next) {
if(!req.header('authorization')) {
return res.status(401).send({message: 'Unauthorized request. Missing authentication header'});
}
let token = req.header('authorization').split(' ')[1];
let payload = jwt.decode(token, '123');
if(!payload) {
return res.status(401).send({message: 'Unauthorized request. Authetication header invalid'});
}
req.user = payload;
next();
}
router.route('/:user_id')
.get((req, res) => {
User.findById(req.params.user_id, (err, user) => {
if (err) {
res.send(err);
} else {
res.json(user);
}
});
})
There are a few options here. I typically use:
router.use('*', checkAuthenticated);
Another option is:
router.get('/:user_id', checkAuthenticated, (req, res) => { ... })
Or, using your example of router.route...:
router.route('/:user_id').get(checkAuthenticated, (req, res) => { ... })
You can also chain them together:
router.route('/:user_id').get(checkAuthenticated).get((req, res) => { ... })
check this hope it will help you
router.route('/:user_id')
.all((req, res, next) => {
if (req.user) {
next();
} else {
res.redirect('/');
}
})
.get((req, res) => {
res.json(req.user);
});

many functions in one middleware expressjs restful api

I have a doubt about middelware in express.
I want to many thinks in one middleware. For example
I have this code y me middleware
module.exports = function(req,res,next) {
if(req.method === 'GET') {
res.end('GET method not supported');
} else {
next();
}
};
and I use it like this
app.route('/', <the_middleware>, (res, req, next) => {
// Code
})
But I am wondering if is possible to do something like this
app.route('/', <the_middleware>.<the function1>, (res, req, next) => {
// Code
})
app.route('/', <the_middleware>.<the_function2>, (res, req, next) => {
// Code
})
is there a possiblitity to do something like
function function1 (req,res,next) {
if(req.method === 'GET') {
res.end('GET method not supported');
} else {
next();
}
};
function function2 (req,res,next) {
if(req.method === 'GET') {
res.end('GET method not supported');
} else {
next();
}
};
module.exports = <I don`t know what go here>
Thanks.
Update. IT works, my code now is
The router
router.post('/', checkAuth.sayHi, checkAuth.sayBye, (req, res, next) => {
console.log('good');
res.status(200).send('it works');
console.log('yes');
});
The middleware
module.exports = {
sayHi(req, res, next) {
console.log('hi');
next();
},
sayBye(req, res, next) {
console.log('bye')
next();
}
};
You can just export an object containing both functions:
module.exports = {
function1,
function2
}

Is there a way to avoid multiple next() in express middleware

This is how I've designed my route and I'm not really happy with it. I'd rather be able to break down each hasValid into its own middleware, but I don't see how that would work since it wouldn't stop execution.
const secretSender = async (req, res, next) => {
if (!hasValidA(req)) {
return next()
}
if (!hasValidB(req)) {
return next()
}
if (!hasValidC(req)) {
return next()
}
if (!hasValidD(req)) {
return next()
}
res.send('something secret')
}
router.use(secretSender)
router.get('*', (req, res) => {
res.send('something public')
})
It also doesn't really make sense to make the default route "something secret" and have "something public" be the middleware since "something public" is the default behavior.
Here's one way to break down each hasValid into its own middleware. Each middleware will short-circuit the execution if the outcome is valid:
const validA = async (req, res, next) => {
if (hasValidA(req)) {
res.send('something secret')
} else {
next()
}
}
const validB = async (req, res, next) => {
if (hasValidB(req)) {
res.send('something secret')
} else {
next()
}
}
const validC = async (req, res, next) => {
if (hasValidC(req)) {
res.send('something secret')
} else {
next()
}
}
const validD = async (req, res, next) => {
if (hasValidD(req)) {
res.send('something secret')
} else {
next()
}
}
router.use(validA, validB, validC, validD)
router.get('*', (req, res) => {
res.send('something public')
})
Update
To achieve somewhat similiar result with OP's code, but only with single next():
const secretSender = async (req, res, next) => {
if (hasValidA(req) && hasValidB(req) && hasValidC(req) && hasValidD(req)) {
res.send('something secret')
} else {
next()
}
}
router.use(secretSender)
router.get('*', (req, res) => {
res.send('something public')
})

middleware is not working in nodejs

I have this code:
exports.get_transducer_edit = (req, res) => {
if(req.isAuthenticated()){
Transducer.findById(req.params.id, (err, foundTransducer) => {
if(err){
res.redirect('/en/dashboard');
} else {
res.render('dashboard/transducer_edit-dashboard', {transducer: foundTransducer});
}
});
}else{
req.flash('error','You need to log in to do that');
res.redirect('/dashboard/login');
}
};
it runs with no problem, but then when I created a middleware in middleware/index.js:
var middlewareObj = {};
middlewareObj.isLoggedIn = function(req, res, next){
if(req.isAuthenticated() ) {
return next();
}
res.redirect('/dashboard/login');
};
module.exports = middlewareObj;
I called it inside this code:
const middleware = require('../middleware');
const Transducer = require('../models/productTransducers');
exports.get_transducer_edit = middleware.isLoggedIn, (req, res) => {
Transducer.findById(req.params.id, (err, foundTransducer) => {
if(err){
res.redirect('/en/dashboard');
} else {
res.render('dashboard/transducer_edit-dashboard', {transducer: foundTransducer});
}
});
};
What am I doing wrong? Please help...
Sorry, I just solved.
I called the middleware in my route:
router.get('/en/dashboard/products/transducers/:id/edit', middleware.isLoggedIn, transducer_controller.get_transducer_edit);
I was trying to call it in my controller like:
exports.get_transducer_edit = middleware.isLoggedIn, (req, res) => {
...
wrong!
Thanks again.

Reduce code repetition in express API route

I'm learning express and am currently writing an API, and have this structure:
app.route('/api/brief/:_id')
.get(function(req, res, next) {
// Check if the _id is a valid ObjectId
if (mongoose.Types.ObjectId.isValid(req.params._id)) {
// Do something
}else{
// Error
}
})
.put(function(req, res, next) {
// Check if the _id is a valid ObjectId
if (mongoose.Types.ObjectId.isValid(req.params._id)) {
// Do something
}else{
// Error
}
})
.delete(function(req, res, next) {
// Check if the _id is a valid ObjectId
if (mongoose.Types.ObjectId.isValid(req.params._id)) {
// Do something
}else{
// Error
}
});
Ideally I'd like to avoid the repetition (checking the validity of the ID).
Is there a way that I can structure the route as to avoid that repetition?
There are a few ways you can approach it. There is the app.all() method:
app.all("/api/*", function(req, res, next) {
if (req.params._id) {
if (mongoose.Types.ObjectId.isValid(req.params._id)) {
return next();
}
else {
// error handle
}
}
next();
});
Personally, I don't like catch-alls. I'd rather be more explicit:
function validateMongooseId (req, res, next) {
if ( mongoose.Types.ObjectId.isValid(req.params._id) ) {
return next();
}
else {
// error handle
}
}
function handleGet(req, res, next) {}
function handlePost(req, res, next) {}
function handlePut(req, res, next) {}
app.post("/api/brief", handlePost);
app.get("/api/brief/:_id", validateMongooseId, handleGet);
app.put("/api/brief/:_id", validateMongooseId, handlePut);
I put the .post() in there to demonstrate why I don't like the catch-all. It clearly doesn't apply to that endpoint. You may have other middleware functions that apply to it, so I'd rather explicitly have them on the endpoints that use them.

Resources