Search code examples
javascriptnode.jses6-promiseamazon-product-api

How to chain multiple paging request with node-apac?


I'm new to Javascript and Nodejs and I am trying to setup a server which can request multiple ItemPages from amazon-product-api via the node-apac node package. So far my http server is up and running with some routes defined. I can also request a single ItemPage. But I have trouble chaining the requests.

example for theQuery:

var query = {
    Title: theTitle,
    SearchIndex: 'Books',
    BrowseNodeId: '698198',
    Power: 'binding:not (Kindle or Kalender)',
    Sort: '-publication_date',
    ResponseGroup: 'ItemAttributes,Images',
    ItemPage: 1
};

the code:

AmazonWrapper.prototype.getAllPagesForQuery = function(theMethod, theQuery, theResultCallback) {    
    client.execute(theMethod, theQuery).then(function(theResult) {
        var pageCount = theResult.result.ItemSearchResponse.Items.TotalPages;
        var requests = [];
        for(var i = 2; i < pageCount; i++) {
            theQuery.ItemPage = i;
            requests.push(client.execute(theMethod, theQuery));     
        }
        Promise.all(requests).then(function(theResults) {       
            var data = theResults[0];
            for(var i = 1; i < theResults.length; i++) {
                var items = theResults[i].result.ItemSearchResponse.Items.Item;
                data.result.ItemSearchResponse.Items.Item.concat(items);
            }
            theResultCallback(data);
        });
    });
};

As you see I want to read from the first request how many Itempages are available for my ItemSearch und create a new request for each Itempage. Unfortunately Promise.all(...).then() is never called.

Any help is appreciated


Solution

  • theQuery looks like an object. As such, it is passed by pointer to when you do theQuery.ItemPage = i and then you pass theQuery, you're passing the same object to every single request and just overwriting the ItemPage property on that one object. This is unlikely to work properly.

    I don't know exactly what theQuery is, but you probably need to make copy of it.

    Also, you may as well return a promise from .getAllPagesForQuery() rather than use a callback since you're already using promises. Error handling and chaining is a whole lot easier with promises all the way through.

    You don't quite disclose enough code, but here's the general idea for how to fix:

    AmazonWrapper.prototype.getAllPagesForQuery = function(theMethod, theQuery) {    
        return client.execute(theMethod, theQuery).then(function(theResult) {
            var pageCount = theResult.result.ItemSearchResponse.Items.TotalPages;
            var requests = [];
            for(var i = 2; i < pageCount; i++) {
                // make unique copy of theQuery object
                var newQuery = Object.assign({}, theQuery);
                newQuery.ItemPage = i;
                requests.push(client.execute(theMethod, newQuery));     
            }
            return Promise.all(requests).then(function(theResults) {       
                var data = theResults[0];
                for(var i = 1; i < theResults.length; i++) {
                    var items = theResults[i].result.ItemSearchResponse.Items.Item;
                     data.result.ItemSearchResponse.Items.Item = data.result.ItemSearchResponse.Items.Item.concat(items);
                }
                return data;
            });
        });
    };
    
    // Usage example:
    obj.getAllPagesForQuery(...).then(function(data) {
        // process returned data here
    });