0

I am trying to create a route that makes 2 API calls, the second depends on the results from the first one and only needs to be called if certain criteria are met. Below are the problems I am having.

  1. The finalCheck function seems to get called before the forEach no matter what? Even when wrapped in the if statement
  2. The counter and userNamesAvailable are not available out of the scope they are assigned in.
  3. I am sure there is a better way to do this and would love any relevant advice.

    router.post('/namecheck', async function(req, res, next) {   
      var name = req.body.name;
      var counter = 0
      var domains = []
      var userNamesAvailable = []
      var dotcom = true
      var answer = ''
    
    getDomains(checkDomains)
    
    // Check domain availabilty
    function getDomains (callback) {
      var url='https://api.ote-godaddy.com/v1/domains/available?checkType=FAST'
      Unirest.post(url)
        .headers({
          "Authorization" : "sso-key ",
          "Content-Type": "application/json"
        })
        .send(
          [
            name + '.com',
            name + '.net',
            name + '.org'
          ]
        )
        .end(function(response) { 
          domains=response.body.domains
          console.log(domains)
          callback(domains)
        })
    
    }
     function checkDomains(domains) {
       var d = 0
    
    //If no data is returned send error
    if(!domains) 
    {
      console.log("No data returned")
      return next("No data returned")
    } else {
      //Check how many domains are unavailable
      for(var i=0; i < domains.length; i++) {
        if(domains[i].available == false){
          d = d + 1
          //Flag if the .com is available
          if(domains[i].domain == name + '.com') {
            dotcom = false
          }
        }
      }
    
      if (d >2) {
        console.log("d is greater than 1")
        answer = 'no'
      //If 2 domains are available and one is .com continue
      } else if (d>1 && dotcom =='false') {
        answer = 'no'
      }
    }
    getUsernames(finalCheck)
    }
    
    function getUsernames(callback){
      // Social Sites to Check
      var sitenames = [ 
        'facebook',
        'twitter',
        'instagram',
        'youtube',
        'slack',
        'blogger'
      ]
    
      // Check Usename availabitliy
      let i = 0
      sitenames.forEach(sitename => {
    
      Unirest.post('https://api.namechk.com/services/check.json')
      .headers({
        'AUTHORIZATION': 'Bearer ',
        'Accept': 'application/vnd.api.v1+json',
      }).send({
        'site': sitename, username: name,
      }).end(function(response) { 
        if(response.body.available == false){
          counter ++
        } else {
          userNamesAvailable.push(response.body)
        }
      });
      i++
    });
    console.log(counter)
    console.log(userNamesAvailable)
    if(i == sitenames.length){
      callback(counter, dotcom)
     }
    }
    
    function finalCheck(counter, dotcom) {
      console.log('Start finalCheck')
      console.log(counter)
      console.log(dotcom)
        //Final Check for is a name is a go or not
        //If one social site is not available and the 
        if(counter == 1 && dotcom =='true') {
          console.log(5-counter + ' social sites available')
          res.send("yes");
        } else {
          res.send("no")
        }
      }
     })
    
rsteen76
  • 75
  • 1
  • 10
  • I don't know if this is the issue but you have `d > 1 & dotcom == 'false'` and perhaps you meant `d > 1 && dotcom == false` (ie, change & to && and change 'false' to false). Same changes for finalCheck. – user3094755 Oct 30 '18 at 21:02
  • the callback on `getUsernames` happens before the `forEach` because each of those elements creates an asyncronous call. You need to watch that *all* of those requests end before calling the callback. – EmmanuelB Oct 30 '18 at 21:06
  • Thanks I did catch that conditional but it is not affecting the other code. I realize why the getUsernames getting called but not sure how to structure it correctly. – rsteen76 Oct 30 '18 at 21:16

1 Answers1

3

Following the answer on this question. You should be able to do it using Promise.

You have to change only the function getUsernames.

  function getUsernames(callback) {
    // Social Sites to Check
    var sitenames = [
      'facebook',
      'twitter',
      'instagram',
      'youtube',
      'slack',
      'blogger'
    ];

    // Check Usename availabitliy
    let requests = sitenames.map((sitename) => {
      return new Promise((resolve) => {
        Unirest.post('https://api.namechk.com/services/check.json')
          .headers({
            'AUTHORIZATION': 'Bearer ',
            'Accept': 'application/vnd.api.v1+json',
          }).send({
            'site': sitename,
            username: name,
          }).end(function(response) {
            if (response.body.available == false){
              counter++;
            } else {
              userNamesAvailable.push(response.body);
            }
            resolve();
          });
      });  
    });

    Promise.all(requests).then(() => { 
      console.log(userNamesAvailable);
      callback(counter, dotcom);
    });
  }

  function finalCheck() {
    console.log('Start finalCheck')
    console.log(counter)
    console.log(dotcom)
    //Final Check for is a name is a go or not
    //If one social site is not available and the
    if (counter == 1 & dotcom == 'true') {
      console.log(5 - counter + ' social sites available')
      res.send("yes");
    } else {
      res.send("no")
    }
  }

Remember that asyncronous functions in javascript are a feature and not something you should be fighting (what I think you are trying to do declaring your main function as async function). Try to understand them first and you will notice they are a big advantage.

There is plenty of documentation about them out there... async Fucntion understanding Promises

EDIT: Do not send the variables that you call global as parameters, they are already available in the called function.

EmmanuelB
  • 1,236
  • 9
  • 19
  • Thanks! So I am still wondering why the userNamesAvailable and counter are not available globally? Everything else seems to be working. – rsteen76 Oct 30 '18 at 21:49
  • I will edit my answer to handle your logs of `userNamesAvailable` and increment the counter on each `Unirest.end`, you should see the logs working correctly. – EmmanuelB Oct 30 '18 at 22:07
  • That would work also, I am actually counting the false responses and saving the true ones. I had my code as above but counter and userNamesAvailable are still not available. – rsteen76 Oct 30 '18 at 22:20
  • How do you know they are not available? – EmmanuelB Oct 30 '18 at 22:23
  • The console.log for userNamesAvailable is always [] except inside the loop – rsteen76 Oct 30 '18 at 22:25
  • It is because you are sending it as a parameter to `finalCheck`, I will update my answer to include that change. – EmmanuelB Oct 30 '18 at 22:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/182828/discussion-between-byrdemmanuel-and-rsteen76). – EmmanuelB Oct 30 '18 at 22:44