Search code examples
node.jsfetch-apinode-fetch

How can I implement nested node-fetch calls?


For example, I want to retrieve some data from an API (a User) so I can retrieve more data (a Team associated with that User). Something like:

var fetch = require('node-fetch');

app.get('/users/:username', function (req, res) {   
    var username = req.params.username;
    var user = new Object();
    fetch('https://api.github.com/users/' + username)
    .then(function(res) {
        return res.json();
    }).then(function(json) {
        console.log(json);

        user.handle = json.login;
    }).then(fetch('https://api.github.com/users/' + username + '/repos')
        .then(function(res) {
            return res.json();
        }).then(function(json) {
            console.log(json);
            //user.repos = repos
            var payload = new Object();
            payload.user = user;
            console.log(payload);
            res.send(payload);
        })
    );
});

I'm pretty new to Node, and am having trouble figuring out how to do this correctly. The first fetch call works fine, but the nested one, not so much. There's no error message to point me in the right direction.


Solution

  • You have to change this structure:

    .then(fetch('https://api.github.com/users/' + username + '/repos').then(...))
    

    to this:

    .then(() => fetch('https://api.github.com/users/' + username + '/repos').then(...))
    

    The way you were doing it, you were calling fetch() immediately and then passing its result to .then(). The way you need to do it (2nd option shown above) passes a function reference that can then be called LATER by the promise infrastructure.

    To show in a little more detail you what's actually happening, this is the structure you want:

    .then(function(priorData) {
        return fetch(...).then(...);
    });
    

    This does not execute the fetch until the .then() handler is called and then it returns the new promise from fetch(), thus chaining it into the original chain. The arrow function example shown in the 2nd code block in this answer achieves the same as this last code block.


    As a general comment, your two calls to fetch() are not dependent upon one another so you could run them both at the same time in parallel and that would likely get you a faster end result.

    The general scheme for that would be:

    Promise.all([fetch(url1), fetch(url2)]).then(function(results) {
        // results[0] is result of first fetch
        // results[1] is result of second fetch
    });
    

    Then, inside that .then() handler, you have both results and can use them to formulate your response.