Search code examples
node.jsloopshttprequestnonblocking

making http requests in nodejs loop


Finding it almost impossible to capture the response of http requests in a loop as an array. I can see the array in console.log but when I pass the array to be the response of http server I get a blank array. What am I doing wrong , or are there better ways to do this?

Code :

router.route('/uprns').post(function(request, response){
  response.setHeader('content-type', 'application/text');

  console.log('first element from the array is '+request.body.UPRNS[0]);
  console.log('Number of items in array is '+request.body.UPRNS.length);

if (request.body.UPRNS.length == 0) {
         response.send( 'no UPRNS in request' );
    }

  var output = [];
  var obj = '';

  for( var i = 0; i < request.body.UPRNS.length; i++) {

    obj = request.body.UPRNS[i];

    //Make  HTTP calls to     
    var options = {
      host: 'orbisdigital.azure-api.net',
      path: '/nosecurity/addresses?uprn='+obj // full URL as path
    };

    callback = function(res) {    
      res.on('data', function (chunk) {
        output.push(chunk.toString());
      });

      //the whole response has been recieved
      res.on('end', function () {
        console.log(output);
      });
    }

    Https.request(options, callback).end();
  }

  response.send(output);

}); 

I know there is a lot of talk about blocking process in a for loop , but there is no definitive recommended way to deal with http calls in a loop. Thank you .


Solution

  • Here is the code. See the code for the added comments. Do some reading on asynchronous programming with node.js, here's a starter.

    router.route( '/uprns' ).post( function ( request, response ) {
        response.setHeader( 'content-type', 'application/text' );
        console.log( 'first element from the array is ' + request.body.UPRNS[ 0 ] ); // your  1st element in  JSON array.
    
        console.log( 'Number of items in array is ' + request.body.UPRNS.length );
        var output = [];
        var obj = '';
    
        for ( var i = 0; i < request.body.UPRNS.length; i++ ) {
    
            obj = request.body.UPRNS[ i ];
    
            console.log( obj );
    
            //Make  HTTP calls to
    
            var options = {
                host: 'orbisdigital.azure-api.net',
                path: '/nosecurity/addresses?uprn=' + obj // full URL as path
            };
    
            Https.request( options, callback ).end();
    
        }
    
        var countResponses = 0;
        // Don't make functions in a loop, so I moved this function down
        // here.
        function callback( res ) {
    
            res.on( 'data', function ( chunk ) {
                output.push( chunk.toString() );
            });
    
            // Handles an error
            request.on('error', function(err) {
              console.error(err.stack);
              response.statusCode = 500; // or what ever.
              response.send(500, 'there was an error');
            });
    
            //the whole response has been recieved
            res.on( 'end', function () {
                console.log( output );
                countResponses++;
                if (countResponses === request.body.UPRNS.length) {
    
                    // Previously this code was executed directly 
                    // after the loop finished.  It did not wait for
                    // all the responses, so it sent the empty response.
                    // However, the other console.log(output) statements
                    // were called after this.
                    //
                    // There is a bug here that if request.body.UPRNS.length
                    // is zero, then the user will never get a response.  I 
                    // let you fix this up :).
                    response.send( output );
                }
            } );
    
        }
    
    } );