Combine routes from multiple files in ExpressJS? - node.js

What is the best way to combine routes from two files so Express Router will handle them at the same level? I'm thinking of something like this:
Default Routes File
This file would be generated and overwritten every time the generator runs:
var express = require('express'),
router = express.Router(),
custom = require('./custom.routes');
router.get('/', function (req, res) {
});
router.post('/', function (req, res) {
});
router.put('/', function (req, res) {
});
router.use('/', custom);
module.exports = router;
Custom Routes File
This file would only be generated the first time and would never be overwritten.
var express = require('express'),
router = express.Router();
router.post('/custom-method', function (req, res) {
});
module.exports = router;
Parent Route File
This file is generated and overwritten constantly. It is responsible for providing the top level api route:
var express = require('express'),
apiRouter = express.Router();
var widgetRouter = require('./widget.routes');
apiRouter.use('/widgets', widgetRouter);
var sprocketRouter = require('./sprocket.routes');
apiRouter.use('/sprockets', sprocketRouter);
module.exports = apiRouter;
The obvious goal is to allow the developer to customize the routes and know his work will be safe even when the generator is run again.

router.use() does not necessarily need to take you deeper in the tree. You could just add the following line before the exports of the first file.
router.use('/', require('./routes.custom.js'));
With this you can also remove the wrapper from the custom file.

Related

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.

Express call GET method within route from another route [duplicate]

This question already has answers here:
Calling Express Route internally from inside NodeJS
(5 answers)
Closed 3 years ago.
I have multiple routes. How can I get the data from the user's route (GET method), by calling it within the GET method of the group's route? What is the best way of doing this?
My app.js looks like this:
var express = require('express');
var routes = require('./routes/index');
var users = require('./routes/users');
var groups = require('./routes/groups');
var app = express();
app.use('/', routes);
app.use('/users', users);
app.use('/groups', groups);
module.exports = app;
app.listen(3000);
Then I have another file routes/users.js:
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('GET ON THE users!');
});
module.exports = router;
And another route routes/groups.js:
var express = require('express');
var router = express.Router();
var otherRouter = require('./users')
/* GET groups listing. */
router.get('/', function(req, res, next) {
// call the get on users and retrieve all data from that request
res.send('GET for the groups');
});
module.exports = router;
You shouldn't use routing for that. Just call the function responsible for retrieving the users from the GET groups route and do what you need with that data. The way you propose is much more expensive because you will have to make a http call.
For simplicity I'm assuming that your logic is synchronous and data stored in data/users.js:
var data = [{id:1, name: "one"},{id: 2, name: "two"}];
module.exports = function(){
return data;
};
in routes/users.js:
var express = require('express');
var router = express.Router();
var getUsers = required('./../data/users');
router.get('/', function(req, res, next) {
res.send(getUsers());
});
in routes/groups.js:
var express = require('express');
var router = express.Router();
var otherRouter = require('./users')
var getUsers = require('./.../data/users');
router.get('/', function(req, res, next) {
var users = getUsers();
//do some logic to get groups based on users variable value
res.send('GET for the groups');
});
I consider what was being explained "forwarding", and it's quite useful, and available in other frameworks, in other languages.
Additionally, as a "forward" it does not have any overhead from a subsequent HTTP response.
In the case of Express, the following is available in version 4.X. Possibly other versions, but I have not checked.
var app = express()
function myRoute(req, res, next) {
return res.send('ok')
}
function home(req, res, next) {
req.url = '/some/other/path'
// below is the code to handle the "forward".
// if we want to change the method: req.method = 'POST'
return app._router.handle(req, res, next)
}
app.get('/some/other/path', myRoute)
app.get('/', home)
You can use run-middleware module exactly for that
app.runMiddleware('/pathForRoute',{method:'post'},function(responseCode,body,headers){
// Your code here
})
More info:
Module page in Github & NPM;
Examples of use run-middleware module
Disclosure: I am the maintainer & first developer of this module.
For people coming here from google. If you need to hit one or more of your routes and skip the http request you can also use supertest.
const request = require("supertest");
app.get("/usersAndGroups", async function(req, res) {
const client = request(req.app);
const users = await client.get("/users");
const groups = await client.get("/groups");
res.json({
users: users.body,
groups: groups.body
});
});
You can also run them concurrently with Promise.all
I've made a dedicated middleware for this uest, see my detailed answer here: https://stackoverflow.com/a/59514893/133327

Create nodejs express 4 route on runtime

I am trying to create a route on runtime. I am trying to create a flat url structure so if we add an article it will create a slug for it and will create a new route.
I use express 4 new router function
app.js
var express = require('express');
var routes = require('./routes.js');
app.use('/', routes);
var server = http.createServer(app).listen(app.get('port'));
routes.js
var express = require('express');
var router = express.Router();
router.get('/new' ,site.new);
module.exports = router;
I tried creating a function in the router and calling it from the app.js also creating a function in the router while sharing the app instance accross the files
module.exports = app;
and calling it
var app = require("./app.js");
It doesnt seem to work any other idea ?
update:
I have a file called helpers.js and i added the following function
module.exports={
addRoute:function(){
var express = require('express');
var router = express.Router();
var app = require('../app.js');
var routes = require('../routes.js');
router.get('/book', function (req, res) {
res.send('Hello World!');
});
app.use('/book', router);
},
I end up doing that
addRoute:function(){
var express = require('express');
var router = express.Router();
var routes = require('../routes.js');
var app = require('../start-freedom1.js');
router.get('/book' ,function (req, res, next) {
res.send({"data":"kaki","values":"","errors":""});
});
for(var layer in app._router.stack){
if(app._router.stack[layer].name=="router"){
app._router.stack[layer].handle.stack.splice(0, 0, router.stack[0]);
console.log(app._router.stack[layer].handle.stack)
break;
}
}
// / app.use('/', routes);
},
the problem that i had router.get("*"..... at the end of the rout file so i always saw 404
I think that what you are looking for is passing parameters in the URL which you can extract and then use to do some processing. You can do something like below:
app.get('/article/:article_id', function(req, res){
art_id = req.params.article_id;
//query database using art_id
}
If you want to use query parameters instead (with "...../article?id=234") then you would have to use req.query. Have a look at the following page http://expressjs.com/en/api.html#req.params.
Request parameters are considered best practice as they are more readable and are also SEO friendly. You can edit your model to store the article slug as a field but should be unique, that way they can be used to query your DB.

MEAN STACK Routing - doing order

I am a MEAN stack beginner and i cannot find a solution for my routing problem.
I would like to divide all routes from the app.js file, so i create a file which contains all routes of my application.
I get a NOT FOUND issue or an infinite cycle request.
This is what i have in my app.js
app.use(require('./routes/config'));
And here what there is in the routes/config
var express = require('express');
var router = express.Router();
router.get('/partials/:name', require('./partials'));
router.get('/api/tickets', require('./api/tickets'));
router.get('/tickets', require('./tickets'));
router.get('/', require('./index'));
module.exports = router;
and in one route i have:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index');
});
module.exports = router;
Could you please help me and tell me what is wrong and why?
Thanks in advance.
in your config file you need to use the router like this:
router.use('/partials/:name', require('./partials'));
and for the partials will be a route, in your partials file omit the next attribute;
router.get('/', function(req, res) {
res.render('index');
});

Express 4 router

At this point, I am pretty clear on how the Express 4 router works, but I am confused about how the primary router instance declared in the app.js file, like it is immediately below, interacts with other routers in the Express server.
so you start off with this in your app.js file:
var express = require('express');
var router = express.Router();
var app = express();
in your Express 4 app.js file you will then do:
app.use(router); //what is this doing? maybe nothing
then you might do (in the same file app.js):
var loginRoute = require('../routes/login');
var logoutRoute = require('../routes/logout');
app.use('/login',loginRoute);
app.use('/logout',logoutRoute);
and inside loginRoute we have
var express = require('express');
var router = express.Router();
router.get('/',function(req,res,next){
}
router.post('/',function(req,res,next){
}
and in logoutRoute we might have pretty much the same skeleton as loginRoute:
var express = require('express');
var router = express.Router();
router.get('/',function(req,res,next){
}
router.post('/',function(req,res,next){
}
I am warming up to this new router for Express 4, but I still am in the dark about how it works. So my question is, how does the Express router in app.js interact with the other routers?
and what exactly does the line app.use(require('express').Router()) supposed to be doing? My guess is that calling app.use(router); tells Express 4 about your intentions - your intention to use that router instead of the single basic router for app.
But given the code, I don't see how app.use(router) interacts or has anything to do with the routers used by app.use('/login'..) and app.use('/logout'..).
Can Express 4 routers delegate to each other? Can you give an example of this?
I hope your understand my confusion.
One way to think about routers in Express 4+ is as micro-services that can be mounted on either the app itself or on other routers.
For example when mounting on the app itself:
var routerA = express.Router();
var routerB = express.Router();
routerA
.post('/bar', function (req, res, next) {...})
.get('/bar', function (req, res, next) {...});
routerB
.post('/bar', function (req, res, next) {...})
.get('/bar', function (req, res, next) {...});
// Mount routerA at `/foo`
// handles both get and post requests to /foo/bar but not /bar/bar
app.use('/foo', routerA);
// Mount routerB at `/bar`
// handles both get and post requests to /bar/bar but not /foo/bar
app.use('/bar', routerB);
And if you wanted to mount one router to another:
var routerA = express.Router();
var routerB = express.Router();
routerA
.post('/bar', function (req, res, next) {...})
.get('/bar', function (req, res, next) {...});
routerB
.post('/bar', function (req, res, next) {...})
.get('/bar', function (req, res, next) {...});
// Mount routerB to routerA at `/foo`
// handles both get and post requests to /foo/bar at routerA's mount point
routerA.use('/foo', routerB);
// Mount routerA at `/foobar`
// handles both get and post requests to /foobar/bar with routerA
// and /foobar/foo/bar with routerB
app.use('/foobar', routerA);
Using routers in this way can make your code a bit more modular while also allowing for things like this.
Regarding the use of app.use(router) without anything assigned to that router: it's useless. You could remove it without an impact to the application. The routers that are mounted after are the ones actually doing the routing.

Resources