Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

JavaScript Node.js Basics (2014) Building a Command Line Application Perfecting: Getting Multiple Profiles

How to parse JSON on multiple pages?

I’m trying to parse information about products in json format from an online store: at http://raredevice.net/products.json. The problem, however, is that the above URL is actually http://raredevice.net/products.json?page=1 i.e. only page 1 and the products information is laid out on multiple pages! Coincidentally, there are exactly 13 pages and if you enter http://raredevice.net/products.json?page=14 you will find that the products list is empty. Even if you enter any other number outside the range (1=< page <= 13) such as http://raredevice.net/products.json?page=100000 it would still be a valid URL except that the products list would still be zero.

I need a way to parse the JSON on these multiple URLs without having to know in advance how many pages the product lists are laid out on. As explained above, the only way to do that is to check the length of the products list on every page and exit if the length is equal to 0. I’m having problems with the exiting part. I’m not sure how to return from the function in

response.on('end', function() {} )  

so that I return from

var request = http.get("http://raredevice.net/products.json?page=" + page, function(response) {} )

And

function getProducts(page) {}

So far, I’m setting a variable endOfPages to false in the beginning and change it to true once on a given page the list of products is 0. I call the getProduts(page) in a while loop and try to break out of it if endOfPages === true. However, the loop doesn’t seem to stop or possibly does but too late. This is probably because of the asynchronous, non-blocking feature of node.js since the loop keeps executing while the callback functions are still executing.

I’m sure there’s a better way to do all this and I’d appreciate some help :)

// import node.js's http module
var http = require("http");

// global variable
var endOfPage = false;


function printMessage(page) {
    var message = "on page " + page;
    console.log(message);
}
// Print out error messages
function printError(error) {
    console.error(error.message);
}


function getProducts(page) {

    // 1. Connect to the API URL page= 1 to n where n is not known in advance
    var request = http.get("http://raredevice.net/products.json?page=" + page, function(response) {

        var stringBody = "";

        // 2. Read the data
        response.on('data', function(chunk) {
            stringBody = stringBody + chunk;
        });

        response.on('end', function() { 

            if(response.statusCode === 200) {
                try {   
                    // 3. Parse the Json data
                    var jsonBody = JSON.parse(stringBody); 

                    var productsArray = jsonBody.products;

                    /* ******************************* */
                    // EXIT if reached end of pages
                    if (productsArray.length === 0) {
                        // HOUSTON, WE HAVE A PROBLEM !!!
                        // ABORT!
                        // BUT, BUT HOW??
                        // return!
                        // Can't return fast enough for caller to shop calling!
                        endOfPage = true;
                    }
                    /* ******************************* */

                    // 5. Print the data
                    printMessage(page);
                } 
                catch(error) {
                    // Parse Error
                    printError(error);
                }
            }
            else {
                // status Code Error 
                printError({message: "There was an error getting the jsonBody for page" + page + ": " + response.statusCode + " " + response.statusMessage});
            }
        });
        });

       // Connection Error
        request.on("error", printError); 
}



var numPage = 1;

while (true) {

    getProducts(numPage);

    // Never breaks out of loop !
    if (endOfPage === true) {
        break;
    }

    numPage++;
}

1 Answer

The thing about pagenation is that the server has to be the one to tell you when it's out of pages. A proper API would have parameters to request the next, previous, first, and last pages. Something tells me that what you're looking at isn't meant to be a publicly consumed API, so your options are limited. I think you're on the right track, though. try/catch blocks work by handling exceptions. See if this helps:

if (productsArray.length === 0) {
                        throw(new EndOfDataException());
                    }

Elsewhere, define the exception

function EndOfDataException() {
   this.name = "EndOfDataException";
   this.message = "There are no more pages to view";
}