Home > database >  Node.js - Getting stuck recursively trying to make get requests via fetch api
Node.js - Getting stuck recursively trying to make get requests via fetch api

Time:02-20

I am querying an endpoint and need to hit it multiple times to get all of the data. I am trying to do this recursively as I have no idea how many hits at any given time I would need to make to get the full dataset.

I am really coming unstuck due to the way node is non-blocking. I understand why it needs to be as it is single threaded. However, I am struggling implementing my code in a way that will give me the desired output.

The more im reading on here, the more im coming unstuck.

I simply need my functions to hit an endpoint repeatedly until I have pulled all of the data. Then I would like to push this data to an array. Then I would like to work with the data.

-Function to query endpoint

async function getTwitch(url = "", data = {}) {

const response = await fetch(url, {
  method: 'GET', // *GET, POST, PUT, DELETE, etc.
  headers: {
    'Content-Type': 'application/json',
    "Authorization": "Bearer superSecret",
    "Client-ID": "0asdbn3245kas364"
    // 'Content-Type': 'application/x-www-form-urlencoded',
  }
  
});
  return response.json(); // parses JSON response into native JavaScript objects
}

-Callback and Global Variables

let test_BreakCase = 10;
let streams = [];

async function getLiveStreams(cursor = ''){

  //create query parameter for pagination and build into url
  let query = (cursor !== '') ? `after=${cursor}&` : '';
  let baseURL = `https://api.twitch.tv/helix/streams?${query}first=100&language=en`;

  //make fetch req for page; when promise returns iterate it and push data into array
  getTwitch(baseURL)
  .then(data => {
    let cursor = data.pagination.cursor;
    for(let i = 0; i < data.data.length; i  ){
      streams.push(data.data[i].user_login);
    }

    //if cursor not empty recursively call getTwitch()
    if(cursor !== '' && data.pagination !== null && test_BreakCase > 10){
      getLiveStreams(cursor);
    }
  });
}

-Feeble attempt to check for values in the array

const s = await getLiveStreams().then(data => {
  console.log(streams);
});

Thank you

CodePudding user response:

I'm no expert but when I start trying to store the output of recursive functions outside the function before it's finished being called, I'm usually doing something wrong. What if you pass the streams array to the recursive function as you go? This also solves the other possible issue I noticed, which is that usually both the base and recursive cases should return something, whether it's the final result or another recursive call. We keep returning a call to getLiveStreams until the final array of data is returned, which bubbles up the call stack to the initial call to the recursive function.

async function getLiveStreams(cursor = '', streams = []) {
    //create query parameter for pagination and build into url
    let query = cursor !== '' ? `after=${cursor}&` : ''
    let baseURL = `https://api.twitch.tv/helix/streams?${query}first=100&language=en`

    const data = await getTwitch(baseURL)
    cursor = data.pagination.cursor
    for (let i = 0; i < data.data.length; i  ) {
        streams.push(data.data[i].user_login)
    }

    // base case: cursor is empty
    if (cursor === '' || data.pagination === null) {
        return streams
    }

    // recursive case
    return await getLiveStreams(cursor, streams)
}

Edit: the return in the recursive case should probably be an await too, since the function returns a promise.

Edit2: I tested this slightly re-written version of your code with jsonplaceholder and it worked:

const https = require('https')
const _URL = 'https://jsonplaceholder.typicode.com/posts/'

async function getTwitch(url) {
    return new Promise((resolve, reject) => {
        let data = ''
        https.get(url, (res) => {
            res.on('data', (chunk) => {
                data  = chunk
            })
            res.on('end', () => resolve(JSON.parse(data)))
        })
    })
}

async function getLiveStreams(i = 1, streams = []) {
    let baseURL = _URL   i.toString()

    const data = await getTwitch(baseURL)

    streams.push(data)

    // base case: we've made 50 requests
    if (i === 50) {
        return streams
    }

    // recursive case
    return await getLiveStreams(i   1, streams)
}

getLiveStreams().then(results => console.log(results))
  • Related