Luke Schlangen
Luke Schlangen

Reputation: 3882

Using async/await recursively with node request package

I'm making an http request using the response node library and I am trying to call it recursively (If the user made a commit on one day, check the previous day. If not, count up all the days to get the streak).

The problem is that the line

const githubResponse = await request(options);

Spits out the error

Unexpected token o in JSON at position 1

await request(options) doesn't seem to return the JSON GitHub API response I am expecting, but instead githubResponse seems to be an object that I can't use. I'm guessing I'm using async/await improperly, but I'm not sure how to fix it.

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };
    const githubResponse = await request(options)

    // I get an error on the next line

    if (JSON.parse(githubResponse).total_count > 0) {
        const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
        let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
        streakCounter++;
        console.log('streakCounter', streakCounter);
        return streakCounter;
    } else {
        return 0;
    }
}

UPDATE: It seems like this is not a promise, so I need to format this differently (as a callback). When I try this:

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };
    request(options, async function (error, response, body) {
        console.log('error:', error); // Print the error if one occurred
        if (JSON.parse(body).total_count > 0) {
            const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
            let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
            streakCounter++;
            console.log('streakCounter', streakCounter);
            return streakCounter;
        } else {
            return 0;
        }
    });
}

The line

let streakCounter = await checkUserCommitForDate(user, previousDaysDate);

becomes the problem as streakCounter is undefined, making the log NaN.

Upvotes: 0

Views: 1639

Answers (3)

Nagaraja Malla
Nagaraja Malla

Reputation: 164

If you are upgraded to Node 8 LTS, then native util.promisfy can be used as below:

const { promisify } = require('util')
const request = promisify(require('request'))

async function checkUserCommitForDate(user, date) {
  const options = {
    url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
    headers: {
      'User-Agent': 'request',
      'Accept': 'application/vnd.github.cloak-preview',
      'json':true
    }
  };

  try{
    const githubResponse = await request(options);
    if (githubResponse.body.total_count > 0) {
      const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
      let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
      streakCounter++;
      console.log('streakCounter', streakCounter);
      return streakCounter;
    } else {
        return 0;
    }
  }
  catch(err){
    console.error(err)
    return 0;
  }
}

Using json:true in the options, will reduce another step to parse as the response will be in JSON format.

Upvotes: 1

Enrique Fueyo
Enrique Fueyo

Reputation: 3488

As said in the comments request uses callbacks instead of returning a promise and you dont really need to promisify it by yourself since there's already a pacakge for that called request-promise.

Using it in your code should directly work out of the box with async/await

Upvotes: 2

Luke Schlangen
Luke Schlangen

Reputation: 3882

I used promisify example from here to convert it to this and it worked!

async function checkUserCommitForDate(user, date) {
    const options = {
        url: `https://api.github.com/search/commits?q=author:${user}+author-date:${date}`,
        headers: {
            'User-Agent': 'request',
            'Accept': 'application/vnd.github.cloak-preview'
        }
    };

    const githubResponse = await promisify(request)(options);

    if (JSON.parse(githubResponse.body).total_count > 0) {
        const previousDaysDate = moment(date).subtract(1, 'day').format('YYYY-MM-DD');
        let streakCounter = await checkUserCommitForDate(user, previousDaysDate);
        streakCounter++;
        console.log('streakCounter', streakCounter);
        return streakCounter;
    } else {
        return 0;
    }
}

function promisify(fn) {
    return function (...args) {
        return new Promise((resolve, reject) => {
            fn(...args, (err, result) => {
                if (err) return reject(err);
                resolve(result);
            });
        });
    };
};

Upvotes: 2

Related Questions