I have a middleware, which checks to admin logged in or not. And it's works for all /admin routes.
But I have a route for admin logins and it has a route like this: /admin/login. That's why login page is not opening. I want to prevent that middleware on this specific route. How can I do this?
These are my routes:
app.use('/', favoriteBlogsMW, indexGetRoutes, indexPostRoutes)
app.use('/admin', adminAuthMW, adminGetRoutes, adminPostRoutes)
Here is login page route, which I want to prevent middleware for in adminGetRoutes.
//this route works like this: /admin/login
router.get('/login', (req, res) => {
if(req.cookies.jwt){
res.redirect('/admin')
} else {
res.render('admin/login')
}
})
You could set the middleware after defining the /login route.
Create a separate file that contains all the routes and export Router from this file.
// adminRoutes.js
const express = require("express");
const router = express.Router();
// define "/login" route
router.get('/login', (req, res) => { ... });
// add the middleware
router.use(adminAuthMW);
// define the routes that need the "adminAuthMW" middleware
router.post(...)
router.get(...)
...
module.exports.adminRouter = router;
And in the main file,
Change
app.use('/admin', adminAuthMW, adminGetRoutes, adminPostRoutes)
to
app.use('/admin', adminRouter);
You could do it inline as well. I prefer it that way. like this on the server:
app.use('/admin', require('../login'))
And the route file like this:
router.post('/', (req, res) => {
res.render('login', {title: 'User', user})
}
you can use res.redirect() method/function instead of res.render()
res.render() => It only renders the views and doesn't redirect the
routes
code:
router.get('/login', (req, res) => {
if(req.cookies.jwt){
res.redirect('/admin')
} else {
res.redirect('/admin/login')
}
})
Related
app.js:
var app = express();
app.use('/my-page', require('./routes/my-page.js'));
my-page.js:
const router = require('express').Router();
router.get('/one', function (req, res, next) {
return res.send('this is /my-page/one');
});
router.get('/my-other-page', function (req, res, next) {
return res.send('this is /my-other-page');
});
How do I make it so my-other-page isn't under my-page, but is instead on the root? I do not want to change app.js because i still want most routes under that page, just one specific one that I want to not have /my-page.
I tried .. in the route but doesnt work. I tried making app from app.js global, but that didn't seem to work either.
Typically you have a routes.js that can import the other routes. (You don't need to, but I think it will better for your structure).
app.js
var app = express();
app.use('/', require('./routes/routes.js'));
routes.js
const router = require('express').Router();
router.use('/my-page', require('./my-page.js'));
router.use('/my-other-page', require('./my-other-page.js'));
Then you split my-page.js and my-other-page.js.
my-page.js
const router = require('express').Router();
// This is /my-page/one
router.get('/one', function (req, res, next) {
return res.send('this is /my-page/one');
});
my-other-page.js
// This is /my-other-page/one
router.get('/one', function (req, res, next) {
return res.send('this is /my-other-page/one');
});
I have an Express.js app with a Passport-local Auth, I'm tying to implement express router to my app since it's getting really hard to debug
This is an example of my main file (app.js)
const express = require('express')
const app = express()
const passport = require('passport')
const testing = require('./routes/file')
app.use(passport.initialize())
app.use(passport.session())
app.use('/router', testing)
const initializePassport = require('./passport-config');
initializePassport.initialize(passport);
app.get('/', checkAuthenticated, (req, res) => {
let user = data.key
res.send(`Hi ${user}`)
})
app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
app.listen(3000)
This is what my main file is like, this works perfectly fine
and just to make things clear, The function are to check if a user is authenticated or not, also my passport-config returns something called data.key which is basically the username of the user.
Now I've created a router here app.use('/router', testing) with the route as /router for testing purposes
Now this is my file.js that is being used by express
const express = require('express'), router = express.Router();
var bodyParser = require('body-parser');
// Handle POST requests
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/test', checkAuthenticated, (req, res) => {
let user = data.key;
res.send(`Hello ${user}, this is coming from the router`)
})
module.exports = router;
Now as expected when I open the site at localhost:3000/router/test it returns a undefined error for data.key since it's not imported and then when I comment that out the line causing the error then checkAuthenticated doesn't work, even when I'm not logged in I can get access to the page, now this is the problem, how do I fix it, I've gone through the entire express router docs I couldn't find luck there.
Thanks
Your function is not in the global scope you need to set it to global to be able to see it like:
GLOBAL.authFunction = function(){
}
Suggestion:
1- make a module for auth name it authModule.
2- import the module auth check middleware where ever you want.
Im using nodejs/express view engine in my application. This means that when the route points to an existent url, an assigned template would be rendered onto the screen. I have previously implemented a redirect to the homepage whenever a user types in an unexisting url. However, now, I have an wordpress endpoint which is to/stores and I am trying to do a redirect to that instead of a previous template that I had. The issue is that when I click on the href link, it goes straight to homepage, because this time it is not a template, but a route. So it doesnt fit into the 'view engine' type of view. Please see my code below for what I mean. Thanks!
Here in app.js, I am doing the redirecting to the homepage if there is an nonexisting route that:
const express = require('express');
const path = require('path');
const router = require('./routes/index');
const morgan = require('morgan');
const ENVIRONMENT = require('./common/config').ENVIRONMENT;
const BASE_URL = require('./common/config').BASE_URL;
const app = express();
app.locals.BASE_URL = BASE_URL;
app.disable('x-powered-by');
app.use(morgan('combined'));
app.use('/', express.static(path.join(__dirname, '../public')))
app.use('/', router);
app.use(function(req, res) {
res.redirect('/');
});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.listen(3000, () => console.log(`listening in ${ENVIRONMENT} on port 3000!`));
And then in the index.js file, I declare my routes and the corresponding html files that will render. Keep in mind that the /stores route will be a redirect. It previously rendered a html file, but now I would like it to redirect to a wordpress endpoint /to/stores . But the result after clicking the href is going to the homepage.
/* GET home page. */
router.get('/', function (req, res) {
const agentString = req.get('User-Agent');
const referrer = req.get('Referrer');
if ((referrer && referrer.includes('art.vpn.twttr.com/tweet_review')) || (agentString && agentString.includes('AdsBot'))) {
res.render('bots/honeypot');
} else {
res.render('home', {title: defaultTitle, description: defaultDescription});
}
});
router.get('/reddit', function (req, res) {
res.render('bots/honeypot');
});
router.get('/facebook', function (req, res) {
const clientIps = req.headers['x-forwarded-for'];
const userAgent = req.headers['user-agent'];
if(!clientIps || userAgent.includes('facebookexternalhit')){
res.render('bots/honeypot');
return;
}
const ipMatchCidrs = areIp4sInCidrs(clientIps.split(','), BLACKLISTED_CIDRS);
if (ipMatchCidrs) {
res.render('bots/honeypot');
return
}
const path = req.url.split('?');
const queryString = path.length > 1 ? `?${path[1]}` : '';
res.redirect(301, `/${queryString}`);
});
// THIS IS THE ROUTE THAT I AM TRYING TO DO THE 301 REDIRECT
router.get("/stores", (req, res) => {
res.status(301).redirect("/to/stores")
})
router.get('/institutional', function (req, res) {
res.render('institutional');
});
router.get('/institutional/checkout', function (req, res) {
res.render('institutional-checkout');
});
router.get('/go/:page', function (req, res) {
res.render('lps/' + req.params.page);
});
router.get('/api', function (req, res) {
res.render('api');
});
module.exports = router;
It seems that your application doesn't define "/to/stores" route, so user is first redirected to that route and then the catch all middleware redirects the user to homepage.
If you want to redirect user to different application, you need to use the absolute url of that application. i.e. res.status(301).redirect("https://example.com/to/stores")
If instead you want to handle "/to/stores" route in this application you need to add /to/stores route handler to your app, i.e.
router.get("/to/stores", (req, res) => {
//TODO: Handle /to/stores route
});
so I have a route written with app.route:
app.route('/word/:id')
.get(word.getWord)
.put(word.updateWord)
.delete(word.deleteWord);
Now I want to re-write the route with some middleware. I know how to do this route by route, for example the first route would be:
app.get('/word/:id', connect.ensureLoggedIn('/auth/facebook'), word.getWord);
But can I apply the same middleware to all 3 routes at once?
you can use something like
var express = require('express');
var router = express.Router();
// -- #section router middleware
router.use(function (req, res, next) {
/* your code here */
next();
});
// -- #section routes
router.get('/users', function (req, res) {
//res.render('users')
});
router.post('/users', function (req, res) {
});
Suppose I want to have REST endpoints which look roughly like this:
/user/
/user/user_id
/user/user_id/items/
/user/user_id/items/item_id
CRUD on each if makes sense. For example, /user POST creates a new user, GET fetches all users. /user/user_id GET fetches just that one user.
Items are user specific so I put them under user_id, which is a particular user.
Now to make Express routing modular I made a few router instances. There is a router for user, and a router for the item.
var userRouter = require('express').Router();
userRouter.route('/')
.get(function() {})
.post(function() {})
userRouter.route('/:user_id')
.get(function() {})
var itemRouter = require('express').Router();
itemRouter.route('/')
.get(function() {})
.post(function() {})
itemRouter.route('/:item_id')
.get(function() {})
app.use('/users', userRouter);
// Now how to add the next router?
// app.use('/users/', itemRouter);
URL to item is descendents of the URL hierarchy of the user. Now how do I get URL with /users whatever to userRouter but the more specific route of /user/*user_id*/items/ to the itemRouter? And also, I would like user_id to be accessible to itemRouter as well, if possible.
You can nest routers by attaching them as middleware on an other router, with or without params.
You must pass {mergeParams: true} to the child router if you want to access the params from the parent router.
mergeParams was introduced in Express 4.5.0 (Jul 5 2014)
In this example the itemRouter gets attached to the userRouter on the /:userId/items route
This will result in following possible routes:
GET /user -> hello user
GET /user/5 -> hello user 5
GET /user/5/items -> hello items from user 5
GET /user/5/items/6 -> hello item 6 from user 5
var express = require('express');
var app = express();
var userRouter = express.Router();
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var itemRouter = express.Router({mergeParams: true});
// you can nest routers by attaching them as middleware:
userRouter.use('/:userId/items', itemRouter);
userRouter.route('/')
.get(function (req, res) {
res.status(200)
.send('hello users');
});
userRouter.route('/:userId')
.get(function (req, res) {
res.status(200)
.send('hello user ' + req.params.userId);
});
itemRouter.route('/')
.get(function (req, res) {
res.status(200)
.send('hello items from user ' + req.params.userId);
});
itemRouter.route('/:itemId')
.get(function (req, res) {
res.status(200)
.send('hello item ' + req.params.itemId + ' from user ' + req.params.userId);
});
app.use('/user', userRouter);
app.listen(3003);
manageable nested routes...
I wanted a specific example of doing nested routes in a very manageable way in express 4 and this was the top search result for "nested routes in express". Here's an API that would have many routes that would need to be broken up for example.
./index.js:
var app = require('express')();
// anything beginning with "/api" will go into this
app.use('/api', require('./routes/api'));
app.listen(3000);
./routes/api/index.js:
var router = require('express').Router();
// split up route handling
router.use('/products', require('./products'));
router.use('/categories', require('./categories'));
// etc.
module.exports = router;
./routes/api/products.js:
var router = require('express').Router();
// api/products
router.get('/', function(req, res) {
res.json({ products: [] });
});
// api/products/:id
router.get('/:id', function(req, res) {
res.json({ id: req.params.id });
});
module.exports = router;
Nesting example in folder structure
I noticed some comments on "nesting folder structure". It is implied in this however not obvious so I added the section below. Here's a specific example of a nested folder structure for routes.
index.js
/api
index.js
/admin
index.js
/users
index.js
list.js
/permissions
index.js
list.js
This is more a general example of how node works. If you use "index.js" in folders similarly to how "index.html" works in web pages for a directory default, this will be easy to scale your organization based off of recursion without changing your entry points to code. "index.js" is the default document accessed when using require in a directory.
contents of index.js
const express = require('express');
const router = express.Router();
router.use('/api', require('./api'));
module.exports = router;
contents of /api/index.js
const express = require('express');
const router = express.Router();
router.use('/admin', require('./admin'));
module.exports = router;
contents of /api/admin/index.js
const express = require('express');
const router = express.Router();
router.use('/users', require('./users'));
router.use('/permissions', require('./permissions'));
module.exports = router;
contents of /api/admin/users/index.js
const express = require('express');
const router = express.Router();
router.get('/', require('./list'));
module.exports = router;
There is some DRY issues here possibly but it does lend itself well to encapsulation of concerns.
FYI, recently I got into actionhero and have found it to be full featured w/sockets and tasks, more like a true framework all-in-one flipping the REST paradigm on its head. You should probably check it out over going naked w/ express.
var userRouter = require('express').Router();
var itemRouter = require('express').Router({ mergeParams: true });
userRouter.route('/')
.get(function(req, res) {})
.post(function(req, res) {})
userRouter.route('/:user_id')
.get(function() {})
itemRouter.route('/')
.get(function(req, res) {})
.post(function(req, res) {})
itemRouter.route('/:item_id')
.get(function(req, res) {
return res.send(req.params);
});
app.use('/user/', userRouter);
app.use('/user/:user_id/item', itemRouter);
The key to the second part of your question is the use of the mergeParams option
var itemRouter = require('express').Router({ mergeParams: true });
From /user/jordan/item/cat I get a reponse:
{"user_id":"jordan","item_id":"cat"}
Using #Jason Sebring solution, and adapting for Typescript.
server.ts
import Routes from './api/routes';
app.use('/api/', Routes);
/api/routes/index.ts
import { Router } from 'express';
import HomeRoutes from './home';
const router = Router();
router.use('/', HomeRoutes);
// add other routes...
export default router;
/api/routes/home.ts
import { Request, Response, Router } from 'express';
const router = Router();
router.get('/', (req: Request, res: Response) => {
res.json({
message: 'Welcome to API',
});
});
export default router;
In the spirit of Express modular routers, we should have a separate router for users and for items. That router isn't part of our top-level application logic. We can nest it in our users' router instead.
Users router
const users = require('express').Router();
const items = require('./items');
//...
// Our root route to /users
albums.get('/', function(req, res, next) {
// res.send() our response here
});
// A route to handle requests to any individual user, identified by an user id
users.get('/:userId', function(req, res, next) {
let userId = req.params.userId;
// retrieve user from database using userId
// res.send() response with user data
});
// Note, this route represents /users/:userId/items because our top-level router is already forwarding /users to our Users router!
users.use('/:userId/items', items);
//...
module.exports = users;
Items router
// We need to merge params to make userId available in our Items router
const items = require('express').Router({ mergeParams: true });
//...
// The root router for requests to our items path
items.get('/', function(req, res, next) {
let userId = req.params.userId; // Here is where mergeParams makes its magic
// retrieve user's track data and render items list page
});
// The route for handling a request to a specific item
items.get('/:itemId', function(req, res, next) {
let userId = req.params.userId; // <-- mergeParams magic
let itemId = req.params.itemId;
// retrieve individual item data and render on single item page
});
//...
module.exports = items;
Source
try to add { mergeParams: true } look to simple example which it middleware use it in controller file getUser at the same for postUser
const userRouter = require("express").Router({ mergeParams: true });
export default ()=>{
userRouter
.route("/")
.get(getUser)
.post(postUser);
userRouter.route("/:user_id").get(function () {});
}
Express router(express.Router()) keeps params seprate so you would explicitly have to tell express to merge these params.
eg:
express.Router({ mergeParams: true })
//above line is answer to your question.
You need only one router, and use it like this:
router.get('/users');
router.get('/users/:user_id');
router.get('/users/:user_id/items');
router.get('/users/:user_id/items/:item_id');
app.use('api/v1', router);