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
Related
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.
This is my app.js
var express = require('express');
...
var model = require('./models/my_model');
var routes = require('./routes/index');
var app = express();
app.use('/', routes);
var middlewareBefore = function(req, res, next){
my_model.getName(function(err, result){
if(err){
console.log(err);
res.redirect('/error');
}else{
console.log(result);
next();
}
})
}
app.use(middlewareBefore);
...
module.exports = app;
and this is my routes/index.js file
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('login', { url: my_model.getUrl() });
});
module.exports = router();
I'm trying to access my_model from the route file. I've already tried using app.locals, res, req, res.locals and app.use('/', routes)(my_model), as seen on different questions from this page, but none of them seem to work... I wonder if the usage of express.Router() is creating this issue (note that setting the middleware before the route didn't solve this)
Several ways to do that:
1.use app.use('/', routes); after declaration of middlewareBefore variable.
2.or declare my_model directly in routes/index.js at top var model = require('./models/my_model');
and use within router.get().
3.or better use MVC architecture.
I have a Node/Express application, and I need to move one route to a different file.
This is my index.js.
'use strict';
let express = require('express'),
bodyParser = require('body-parser'),
logger = require('morgan'),
_ = require('lodash');
let app = express();
app.use(logger('combined'));
app.use(express.static('public'));
app.use(bodyParser.json({}));
app.use(bodyParser.urlencoded({ extended: true }));
console.log("I am open");
let users = [///stuff ];
let games = [];
// Handle POST to create a user session
app.post('/v1/session', function(req, res) {
// do things
});
// Handle POST to create a new user account
app.post('/v1/user', function(req, res) {
// do things
});
// Handle GET to fetch user information
app.get('/v1/user/:username', function(req, res) {
// do things
});
// Handle POST to create a new game
app.post('/v1/game', function(req, res) {
// do things
});
// Handle GET to fetch game information
app.get('/v1/game/:id', function(req, res) {
// do things
});
let server = app.listen(8080, function () {
console.log('Example app listening on ' + server.address().port);
});
I want to have a new server side route (GET /v1/game/shuffle?jokers=false), but I don't quite understand how to separate it into a new file, perhaps in ./routes/shuffleRoute.js.
I read through this one, but I don't quite understand it due to the file names being similar. How to separate routes on Node.js and Express 4?
And I'm just trying to separate one route, not all.
Create a file in routes, called shuffleRoute.js. In this file write something like
var express = require('express');
var router = express.Router();
router.get("/shuffle", function (req, res, next) {
// magic here
});
router.get("/:id", function (req, res, next) {
// more magic here
});
module.exports = router;
and in your server.js
app.get("/v1/games", require("./routes/shuffleRoute.js"));
It's important to node that in your case, as you are using a param for id, your shuffle route needs to come before the :id route. Otherwise express will interpret shuffle as an id (which will hopefully not be an id)
If you only want to "outsource" "/v1/games/shuffle, make sure that comes before app.get("/v1/games/:id"...) in your server.js file
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.
I am using expressjs and I want get a request object comes form this url
http://www.thedomain.com/membername/category/item?item=abc
in server side. I am trying to use
// app.js
var express = require('express');
var routes = require('./routes/index');
var app = express();
app.use('/*', routes);
In './routes/index':
//'./routes/index''./routes/index'
var express = require('express');
var config = require('../config');
var router = express.Router();
var url = require('url');
/* GET category page. */
router.get('/category', function(req, res, next) {
console.log(' pathname: ',url.parse(req.url).pathname)
res.render('index', {
title: url.parse(req.url).pathname
});
});
Actually, I have no way to get value of membername
I want to know how could I get value of membername before process item value in query string in the category router. I also want to know how to write a regex that accept all value of membername for the router which stay on the front of the category router as a pre-process module.
Thank for all your comment and answer
req.get('/:memberName/category/item', function(req, res, next) {
// do whatever you want with req.prams.memberName here...
next();
});
req.get('/:memberName/category/item', function(req, res, next) {
// now do whatever you want with req.query.item here...
});
Since you suggest you want to restrict only to letters and numbers (and perhaps _ too), use a regular expression:
req.get('/\w+/category/item', function(req, res, next) {
// Access membername via req.params[0]
});
I've had bad luck with Express routes and regular expressions, but I believe that problem has been fixed in Express 4.0.