0

I've written the following lambda function to grab data from an API and drop it into a database. This works fine when the API only returns a single page, however with > 1 page the parseData before the resolve() runs, but the "Function finished" log is never triggered. Is this resolve() not resolving the promise I expect it to?

 exports.handler = async (event, context, callback) => {
  let db = await initDB(); // External function
  await api_get('users')
  console.log("Function finished");
  db.end()
  callback(null)

  function api_get(type, page = 1, count = 0, results = []) {
    return new Promise(async function(resolve, reject) {
        let uri = `https://api.com/v1/${type}`;
        request.get(uri + '?page=' + page, async (error, response, body) => {
          const data = JSON.parse(body);
          results.push(data.users)
          current_count = count + data.meta.count
          if (current_count < data.meta.total) {
              await api_get(type, page + 1, current_count, results);
          }
          else {
              await parseData(type, results)
              resolve()
          }
        });
    });
   }
   
  
   function parseData(type, data) {
      return new Promise(async function(resolve, reject) {
         switch (type) {
            case 'users':
               let users = [].concat(...data)
               let sql = ''
               for (const user of users) {
                  sql = sql + `INSERT INTO users (user_id) VALUES ('${user_id}');`
               }
               db.query(sql)
               .then( () => {
                  resolve()
               })
            break;
         }
      });
   }
 };
Andrew White
  • 600
  • 1
  • 9
  • 29
  • You actually may choose some other library instead of `request`, Then you can use async/await all the way. Related question: https://stackoverflow.com/q/60334548/14032355 – ikhvjs Nov 03 '21 at 08:39

1 Answers1

1

You are not calling resolve() if this condition is met:

      if (current_count < data.meta.total) {
          // If execution go in this block, you are never calling "resolve()"
          await api_get(type, page + 1, current_count, results);
      }
      else {
          await parseData(type, results)
          resolve()
      }
munleashed
  • 1,677
  • 1
  • 3
  • 9
  • Sorry, I may not have been clear. `current_count` increments every call, so the parseData() does run, just the resolve() after it doesn't seem to do what I expect it to – Andrew White Nov 02 '21 at 22:08
  • So I'm expecting to only `resolve()` once the current_count has finished incrementing - i.e. we have all our results and we parse them, then we return back. – Andrew White Nov 02 '21 at 22:13
  • You are basically nesting Promises (because you are in the recursion). So, in each recursive iteration you need to have a resolve() in order to go back all the way to the top call of your recursive function. So in each execution of api_get function you have to have resolve(). if condition (current_count < data.meta.total) is met, you are not calling resolve() at all? – munleashed Nov 02 '21 at 22:23
  • Thanks @munleashed! You were completely right, that worked great. I think I've got some fundamental misunderstandings on how promises work. I'll go do some reading, thanks! – Andrew White Nov 02 '21 at 23:38