JacobZ JacobZ - 6 months ago 44
Node.js Question

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

Answer

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
});