0

I'm trying to get the value returned from an API query, but in all the ways I've done it, it either returns Undefined or [object Promise]. I've tried several solutions and I still haven't got something that works. Below is the last code I made to see if it worked but again without success.

function generateLink(link) {
  const url = 'https://api.rebrandly.com/v1/links';
  const options = {
    method: 'POST',
    uri: url,
    headers: {'Content-Type': 'application/json', apikey: 'xxxxxxxxxxxxxxxxxxxxx'},
    body: JSON.stringify({destination: link})
  };
  return requestPromise(options).then(response => {
      if ( response.statusCode === 200 ) {
          return response.body
      }
      return Promise.reject(response.statusCode)
  })

}
...
bot.onText(/\/offers (.+)/, function onEchoText(msg, match) {
  console.log(match[1]);
  if (isNaN(match[1])) {
    bot.sendMessage(msg.from.id, 'Enter a valid number! \nExample: /offers 5');
  } else {
    client.execute('aliexpress.affiliate.product.query', {
      'app_signature': 'defualt',
      'category_ids': '701,702,200001081,200001388,200001385,200386159,100000616,100001205,5090301',
      'target_currency': 'USD',
      'target_language': 'EN',
      'tracking_id': 'defualt',
      'ship_to_country': 'US',
    }, function (error, response) {
      var code = response.resp_result.resp_code;
      var mesage = response.resp_result.resp_msg;
      if (code === 200) {
        var i;
        var temCupom = [];
        var link = [];
        var itemList = response.resp_result.result.products.product;
        for (i = 0; i < match[1]; i++) {
          temCupom[i] = itemList[i].promo_code_info ? " <b>There's a coupon!</b>: " + itemList[i].promo_code_info.promo_code : "";
          (async () => { 
            link[i] = generateLink(itemList[i].promotion_link).then(body => { return body.shortUrl })
          })();
          bot.sendPhoto(msg.chat.id, itemList[i].product_main_image_url, {
            caption: "❤ <b>Promotion</b> ❤\n" +
              " <b>Price</b>: " + Number(itemList[i].target_sale_price).toLocaleString('en-us', { style: 'currency', currency: 'USD' }) + "\n" +
              " <b>Link</b>: " + link[i] + "\n" +
              temCupom[i],
          });
        }
      }
      else {
        bot.sendMessage(msg.from.id, 'Deu errado! ' + mesage);
      }
    })
  }

});

link[i] need to return the links generated with the API

Wyck
  • 10,311
  • 6
  • 39
  • 60

2 Answers2

0

Option 1 (with async/await):

if (code === 200) {
  var i;
  var link = [];
  var itemList = response.resp_result.result.products.product;
  for (i = 0; i < match[1]; i++) {
    link[i] = await generateLink(itemList[i].promotion_link).then(body => { return JSON.parse(body).shortUrl })
  }
}

Option 2 (with Promise):

if (code === 200) {
  var link = [];
  var itemList = response.resp_result.result.products.product;
  for (let i = 0; i < match[1]; i++) {
    generateLink(itemList[i].promotion_link).then(body => { link[i] = JSON.parse(body).shortUrl })
  }
}

Option 3 (Promise.all takes all URLs in parallel mode):

if (code === 200) {
  const itemList = response.resp_result.result.products.product;
  const requests = itemList.slice(0, match[1])
    .map(item => generateLink(item.promotion_link).then(body => JSON.parse(body).shortUrl));

  const links = await Promise.all(requests);
}

===============================

Updated:

After all, we realized that the body was a string and it was necessary to do JSON.parse

0

You need to assign the result in the then block.

You can make some simple changes, like putting link[i] = result into the then block, but there are problems like the fact that value of i will be the same. Also, if you want the values populated after the for loop, you'll notice that they have not been filled. You need to wait till they are all resolved (faking with timeout below).

function generateLink(link) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(Math.random())
    }, 1)
  })
}

if (200 === 200) {
  var i;
  var link = [];
  var MAX = 10;

  for (i = 0; i < MAX; i++) {
    generateLink('‍♂️').then(result => {
      link[i] = result; // no bueno - since i will be 10 when this is resolved
    })
  }
  console.log(link) // still not resolved

  setTimeout(() => {
    console.log(link) // ‍♂️ [undefined * 9, value] 
  }, 10)
  
}

// async version (note use of `async`)
(async function(){
  var MAX = 10;
  var link = []
  for (i = 0; i < MAX; i++) {
    link[i] = await generateLink('‍♂️')
  }
  console.log(link)// 
})()

So you can add more complexity to make it work, but async/await is likely the way to go if you can support it.

for (i = 0; i < match[1]; i++) {
  link[i] = await generateLink(itemList[i].promotion_link).then((body) => {
    return body.shortUrl;
  });
}

Also if you use await the promises will execute in series, which you might not want. Resolving in parallel is faster, but you could also run into issue if you're going to have too many network requests they'll need to be throttled, so async await may work better)

Daniel
  • 34,125
  • 17
  • 102
  • 150