Dynamic routing from database data - node.js

I'm thinking to implement a small cms just for the fun of it, and what I'd like is for the user to be able to create sites and pages from the cms.
For example there will be some form asking the user for a "site" name and under that site the user will be able to create a site tree of n levels deep which will get saved in a db.
ex: "blah/article", "blah/blah/blah/article".
My issue is how would I implement such routing in expressjs?
How can I declare my routes dynamically based on what the user has created and per site?
If for example I have 2 sites: site1 and site2.
localhost:3000/site1/somepathhere/blah/blah
localhost:3000/site2/someotherpathhere/blah/blah/blah
I want routes for each site to be dynamic (no idea what the user will create) and I want each site routes to apply to that site only and not globally.
So far I playing around with some code but I'm not sure if there is some better way to achieve this.
app.param('site', function(req, res, next, site) {
req.site = site;
next();
});
app.get('/:site', function(req, res) {
res.send(req.site + "<br><pre>" + JSON.stringify(req.params, null, 4) + "</pre>");
});
app.get('/:site/*', function(req, res) {
res.send(req.site + "<br><pre>" + JSON.stringify(req.params, null, 4) + "</pre>");
});

express routing,essentially is playing(parsing and analyzing) with strings. you can implement an url parser that will take the routes you read from database.

Related

Best way to handle dynamic routes with its own logic in ExpressJS?

I've been tasked with something at work that's beyond my current skills so any help is appreciated.
I'm building an admin where you can add "games". Each game needs to have it's own front-end, routes, and logic.
Kinda like,
mainsite.com/game/game1
mainsite.com/game/game2
mainsite.com/game/game3
At the moment I'm just creating a directory based on the game name.
var dir = "./games/" + req.body.gameId;
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
In turn I can pull the .ejs file via:
/* GET dynamic game page. */
router.get("/game/:game", function(req, res, next) {
res.render("../games/"+req.params.game+"/index", { title: "Express" });
});
But I am confused on how it can have it's own logic, routes, connecting to database, front-end, stylesheets inside it's own folder.
There must be a better way to achieve this right?
Cheers
Yes! In Express, you can call app.use() inside a route. You will be able to define a public folder to contain the CSS, JS, and assets that are specific to each route. Just call app.use(express.static('route/to/assets')) inside the route.
app.get('/game/:game', (req, res) => {
app.use(express.static(req.params.game + '/public'))
res.render('../games/' + req.params.game + "/index", { title: "Express" })
})
Seems strange, but perfectly allowed.

how to create multi site url to store particular information to particular site using mongoose

In my Application, there is an option called "create site" that will create a new site URL. So the problem is I'm having so many collections and I need to show related data to the related site.
As an Admin I can create any number of sites and that will contain so many options like "Create User", "my account", "create project", "settings" and etc (In Navbar). So on selecting these options, it should fetch the data related to that option and that site...
For better understanding eg: In my application, Suppose if I create a new site URL something like "www.mywebsite/new-website" -- this URL is a new website it doesn't contain any data by default, all option like "create user, create project, etc.." that will be having data only if I add some data.
I will create another site URL like "www.mywebsite/new-website1" - initial no data will be present, after adding that will be having related information.
In MongoDB how do I achieve this using a single database? so I'm using MEAN stack application I need a solution on how to achieve this scenario, can someone help me to get a clear picture of MongoDB usage in this type of situation that will be appreciated.
Thanks!
By using express routes, a simple way is to nest routers by attaching them as middleware on an other router.
In this way, you can have a collection for websites and use the websiteId as reference in all other collections.
So the routes become:
GET / -> hello websites
GET /new-website -> Hello from Website : new-website
GET /new-website/users -> List users from website : new-website
GET /new-website/users/101 -> Hello User : 101 from website : new-website
var express = require("express");
var app = express();
var siteRouter = express.Router();
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var userRouter = express.Router({ mergeParams: true });
// you can nest routers by attaching them as middleware:
siteRouter.use("/:sitename/users", userRouter);
siteRouter.route("/").get(function(req, res) {
res.status(200).send("hello websites");
});
siteRouter.route("/:sitename").get(function(req, res) {
res.status(200).send("Hello from Website : " + req.params.sitename);
});
userRouter.route("/").get(function(req, res) {
res.status(200).send("List users from website " + req.params.sitename);
});
userRouter.route("/:userId").get(function(req, res) {
res
.status(200)
.send(
"Hello User : " + req.params.userId + " from website :" + req.params.sitename
);
});
app.use("/", siteRouter);
app.listen(3000);
NOTE:- I had only added GET request, use POST request to create websites, users in the responsive routes and sufficient Authorisation has to be checked before giving access to routes.

use dynamic subdomains with nodejs

hello i am new to Nodejs. I want to use dynamic subdomains to access my API and through subdomain prefix I can manage my API data.
Suppose I gave domain like domain:3000 and sub-domain could be a.domain:3000 or b.domain:3000 or anything prefixed to domain:3000.
I used wildcard-domains. but still unable to undersatnd the flow and how to use it and allow organisation listed in DB (Consider prefix as organisation name).
I have used following code:
var wildcardSubdomains = require('wildcard-subdomains')
var checkUser = subdomain('*.localhost:3000', function(req, res,
next) {
console.log(req.session.user.valid);
if(!req.session.user.valid) {
return res.send('Permission denied.');
}
next();
});
app.use(checkUser);
I am also using angularjs and using ui.router to change my states or urls.
I used this module
npm i vhost --save
Here you can see information
http://expressjs.com/en/resources/middleware/vhost.html
wildcard-subdomains
As you can see in https://www.npmjs.com/package/wildcard-subdomains
app.use(wildcardSubdomains({
namespace: 's', // __NAMESPACE_FROM_WILDCARD_CONFIG__
www: 'false',
}))
If you follow, example, link foo.localhost:3000 Express will process this middleware
app.get('/s/foo/', function(req, res){
res.send("Meow!")
})
That is to say
app.get('/__NAMESPACE_FROM_WILDCARD_CONFIG__/__SUBDOMAIN__/', function(req, res){
res.send("Meow!")
})
You can try to write app.get('/s/:subdomain', ...

Dispatch Express.js route based on first parameter?

I'm creating a CMS in node.js and Express. I allow users to create their own subsections in the site. A subsection can be a blog, a page or a forum. These sub-sections can be installed one level deep in the site url path, so for instance:
domain.com/custom-path-blog/
I would have to support the following url structure with express routes:
domain.com/custom-path-blog/ -> blog index
domain.com/custom-path-blog/page/5 -> list posts on page 5
domain.com/custom-path-blog/guides/ -> list posts that belong to guides category
domain.com/custom-path-blog/guides/this-is-a-post -> shows a post
I would also have to support other sub-sections with different url structures. I have to make a call to a database to check out what the first level in the url actually is before I can dispatch it to the appropriate route.
Since this is a saaas website I dont want to dynamically register the routes on my node process as I could end up having thousands of users with possibly millions of routes. This is not doable. I have to go to the database for that first chunk of information.
Once I know a sub section is a blog or a forum or a e-commerce store how do I send the url past that "custom-path-blog" to be processed by the appropriate express routing mechanism?
I'm starting to think this might be too complicated to do with express routes and I will have to do it by hand.
Thanks!
If you have already have 3 separated apps (page, blog, forum), and you want to launch it in 1 node process you can do this:
app.use('/page', pageApp);
app.use('/blog', blogApp);
app.use('/forum', forumApp);
express will strip out the first component of url for you.
In your case, the first component is customize by user, so you need to write a middleware for it:
function appSelector(req, res, next) {
var firstComponent = getFirtCompoent(req.url.pathname) // return page or blog ...
var userID = req.user.id;
detectAppForCurrentUser(firstCompoent, userID, function (type) {
if(type === 'page') {
removeFirstComponent(req);
return pageApp(req, res, next);
}
if(type === 'blog') {
removeFirstComponent(req);
return blogApp(req, res, next);
}
next(); // if not found continue with other routes
}
}
app.use(appSelector);
// TODO other routes here
there are many way to solve problem, but is it important rule: app.use, app.get are called on initialization phase only

access req in expressjs 3 views

Is it possible to access my query params in my views in ExpressJS 3?
I have a url: http://example.com?search=blah
And in my view I would like to access the search param
I can pass it as a locals but wondering if I can access it directly - my experiments were not successful.
Not looking for the pros and cons of direct access - just want to know if it's possible and how.
Here are a few ways to access req.query from your view:
Set it as a local in the call to render
function(req, res) {
res.render('myview', {query: req.query});
};
in your view you can access search as query.search.
Set res.locals
function(req, res) {
res.locals.query = req.query;
res.render('myview');
};
in your view you can access search as query.search.
Use middleware
This is similar to the previous example but we can use middleware in a reusable way.
function(req, res, next) {
res.locals.query = req.query;
next();
};
Any route that uses the above middleware, will have res.locals.query set.
edit
It appears that I misunderstood the question. The intent was to see if the request data could be accessed without use of the above techniques. As far as I know, it can not. Hopefully the above will still be useful for some readers.
I am pretty sure only locals get passed to the view.
Not looking for the pros and cons of direct access - just want to know if it's possible and how.
There are no pros and cons. It's like saying I want to multiply 15 with 0 but I don't want the answer to be apple.
middleware:
function(req, res, next) {
res.locals.param = req.param;
next();
};
view:
<%= param.search %>

Resources