4

I am working on facebook bot, but I am in no way a node.js developer, this being my first time in using it, because I wanted to get out of my comfort zone for a little bit.

This is my request function

function requestExc() {
    var resDictionary = {} 
    unirest.get("http://openapi.ro/api/exchange/" + queryDict["code"] + ".json")
    .query({"date" : queryDict["date"]})
    .end(function(res) {
        if (res.error) {
            console.log('GET error', res.error)
        } else {
            console.log('GET response', res.body)
            resDictionary["rate"] = res.body["rate"]
            resDictionary["date"] = res.body["date"]
        }
    })

    console.log("resDictionary IS " + resDictionary)
    ///prints resDictionary IS [object Object]
    return resDictionary
}

so I am trying to get it's result

var response = requestExc()
if (response !== null) {
    respondToSender(response, sender)
}

and then act accordingly

function respondToSender(res, sender) {
    console.log("RES IS " + res)
    //prints RES IS [object Object]
  if (res["rate"] === null) {
        //do stuff
  }
}

but when the variable gets to the respondToSender it's always undefined.

 TypeError: Cannot read property 'rate' of undefined

I've also tried with Json.parse() but it's the same thing.

trusk
  • 1,634
  • 2
  • 18
  • 32
  • On the one hand, you should probably use `if (response)` instead of `if (response !== null)`; on the other hand, this doesn't answers why it is always undefined. – YakovL Jun 24 '16 at 07:41
  • Thanks, I'll update! – trusk Jun 24 '16 at 07:43

3 Answers3

4

Ok, the problem is unirest (like many node.js modules) works asynchronously meaning that your code is quite probably executed in this order:

var response = requestExc() // request is sent first, ok
if (response !== null) {    // this is done second
    respondToSender(response, sender)
}
                            // the response arrived third, when it is not needed

So to deal with such stuff, you have to use callbacks/end method. See the example here:

unirest.post('http://mockbin.com/request')
.query('name=nijiko')
.query({
  pet: 'spot'
})
.end(function (response) {
  console.log(response); // this is where you should use respondToSender
});

The console.log(response); is launched only when reply came and that's what you want.

YakovL
  • 7,557
  • 12
  • 62
  • 102
  • I've done that. That's where I've started from, and it was the same. Tried returning in .end { return response.body } and it was the same. That's why I've tried to build the dictionary outside, and only return it at the end. – trusk Jun 24 '16 at 08:02
  • I see. To make sure this is the problem, you can also log `response` in main and see the order of those log messages (will probably be first undefined, second object). But what do you mean "the same" for that case? Was `response` undefined in `end` while it was an object in `requestExc`? – YakovL Jun 24 '16 at 08:08
  • The other way. It was an object while printing or accessing in .end but undefined when accessing the value from the function requestExc. – trusk Jun 24 '16 at 08:12
  • @AlexBartiş So that's the way you should work with it: use `requestExc` inside `.end`. Have you tried that? – YakovL Jun 24 '16 at 08:15
  • requestExc is the method that does the request. It would enter an endless loop. – trusk Jun 24 '16 at 08:18
  • @AlexBartiş sorry, I meant `respondToSender` – YakovL Jun 24 '16 at 08:19
  • Yeah, but that doesn't fit my need. I need to run this request multiple times, BUT after I do the first request I need to do something, and after all other requests are finished, I need to do something else. – trusk Jun 24 '16 at 10:20
  • @AlexBartiş Well this is not impossible with asynchronous handling. See this article to get an idea (or rather a complete tool): https://zackehh.com/handling-synchronous-asynchronous-loops-javascriptnode-js/ . This may be of interest, too: http://stackoverflow.com/questions/17607280/why-is-node-js-asynchronous And finally, another article about handling the async nature of Node.js: http://code.tutsplus.com/tutorials/managing-the-asynchronous-nature-of-nodejs--net-36183 Yeap, to use Node.js, you have to get out of your comfort zone :) – YakovL Jun 24 '16 at 15:49
4

Someone from reddit taught me how to add a callback, and now it works as I want it. The complete code is:

// GET a resource
function requestExc(callback) {
    unirest.get("http://openapi.ro/api/exchange/" + queryDict["code"] + ".json")
    .query({"date" : queryDict["date"]})
    .end(function(res) {
        if (res.error) {
            console.log('GET error', res.error)
            callback(res.error, null)
        } else {
            console.log('GET response', res.body)
            callback(null, res.body)
        }
    })
}

and I call it

var response = requestExc(function(error, res) {
            console.log("date array is " + dateArray)
            if (error === null) {
                respondToSender(res["rate"], res["date"], sender, queryDict)
            } else {
                sendTextMessage(sender, "Imi pare rau, dar am intimpinat o problema in comunicarea cu BNR")
            }
        })
trusk
  • 1,634
  • 2
  • 18
  • 32
  • 1
    Yeap, that's what I meant, `respondToSender` in the code below is the same thing as callback. I hope the response was useful at least – YakovL Jun 25 '16 at 12:46
  • @YakovL yes, but it wasn't actually clear for me for me how to use the callback. But now that I see it, it's really simple, and works a lot like our completion handlers in swift. Thank you for all the help! – trusk Jun 26 '16 at 03:09
0

I wrap it in a Promise to get this to work, wondering if this is apt though and if it helps?

return new Promise((resolve, reject) => {
   unirest('GET', 'https://url')
       .headers({
           'Accept': 'application/json'
       })
       .send("")
       .then(function (response) {
           if(!response.error) {
               resolve(response)
           } else {
               reject(response)
           }
       })
});
Joviano Dias
  • 1,043
  • 10
  • 13