19

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;
ggorlen
  • 44,755
  • 7
  • 76
  • 106
asuciu
  • 1,234
  • 2
  • 21
  • 35
  • 2
    Just take the code that figures out what the data response is for the `/users` route and put it in a separate function. Then call that function from both of the places you want to use it. If it's async, then make the function return a promise that gets resolved with the data. You can then use that async interface in both places you need it. – jfriend00 Aug 19 '16 at 20:54
  • You should have posted it as an actual answer. I thought i can invoke the existing routes get method somehow. Thank you for your answer! :) – asuciu Aug 19 '16 at 22:27
  • 1
    I am working on an answer to this same question, as the "you shouldn't do that" answer wasn't good enough for me :) Calling the app directly (similar to how the 'runMiddleware' answer/example does it, except with mocks from https://www.npmjs.com/package/node-mocks-http) I feel would produce a nice 'internal run' capability. That is, `app(mock_req, mock_res)` then examining the response. – ryanm Dec 07 '17 at 18:50
  • duplicates https://stackoverflow.com/q/38946943/133327 – abernier Dec 28 '19 at 21:24

5 Answers5

31

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');
});
vascoFG
  • 129
  • 1
  • 11
Slawomir Pasko
  • 907
  • 8
  • 14
  • That works. Thanks! :D I thought that i can actually do a direct call to the get method for the users router. I don't want to open up a can of warms, but is this a best practice when doing middleware that needs to call a routes methods from within other routes?? Thanks again for you prompt response. – asuciu Aug 19 '16 at 22:31
  • I'm glad I could help. Please mark the question as answered if this suggestion solved the problem. – Slawomir Pasko Aug 21 '16 at 20:38
  • 4
    That's not really any answer to the titular question tho. – Bryan Grace Dec 22 '20 at 04:29
30

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)
conrad10781
  • 2,223
  • 19
  • 17
  • 2
    I believe this answers best the question, whether it is more optimum or not. – htafoya Aug 22 '18 at 04:37
  • I get `TypeError: Cannot read property 'handle' of undefined` – golimar Nov 05 '20 at 15:48
  • 1
    @golimar , presuming you're on 4.X , we would need to see your code to say for certain ( can post in a new question ). But from your message, it looks like ._router is undefined, so it's likely that you're not defining express via the "app" variable as it was in my example, so "app" would need to be updated to whatever the variable you're using is. IE "VARIABLE_YOUR_USING_FOR_EXPRESS._router.handle – conrad10781 Nov 06 '20 at 16:37
13

You can use run-middleware module exactly for that

app.runMiddleware('/pathForRoute',{method:'post'},function(responseCode,body,headers){
     // Your code here
})

More info:

Disclosure: I am the maintainer & first developer of this module.

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
6

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

Stavros
  • 655
  • 7
  • 16
1

I've made a dedicated middleware for this uest, see my detailed answer here: https://stackoverflow.com/a/59514893/133327

abernier
  • 27,030
  • 20
  • 83
  • 114