rucker rucker - 26 days ago 11
Javascript Question

Encapsulating API.ai call into an external javascript function is not working

This code works fine:

var apiai = require('apiai');
var app = apiai(<token>);

var request = app.textRequest('jacket', {
'sessionId': 123456
});

request.on('response', function(response) {
console.log(response);
console.log(response.result.fulfillment.speech);
console.log(response.result.metadata.intentName);
});

request.on('error', function(error) {
console.log(error);
});

request.end();


And it produces the following console output:

{ id: '2865abde-ac8f-4ac3-816e-483c68f709d0',
timestamp: '2016-11-08T22:38:56.461Z',
result:
{ source: 'agent',
resolvedQuery: 'jacket',
action: '',
actionIncomplete: false,
parameters: {},
contexts: [ [Object] ],
metadata:
{ intentId: '357af94f-00b3-4016-a661-732419ddafd6',
webhookUsed: 'false',
intentName: 'clothing' },
fulfillment: { speech: 'clothing2', messages: [Object] },
score: 0.6 },
status: { code: 200, errorType: 'success' },
sessionId: '123456' }
clothing2
clothing


However, when I try to break this apart into a function call, things don't work so well:

File: main.js

var apiai = require('apiai');
var app3 = apiai(<token>);

exports.getresponse = function(inputstring){
var request = app3.textRequest(inputstring, {'sessionId': 123456});
request.on('response', function(response) {
return(response);
});
request.on('error', function(error) {
return(error);
});
request.end();
};


File: moda.js

var express = require("express");
var app = express();
var joe = require('./main.js');
console.log(joe.getresponse('jacket'));
app.listen(3000);


When I run moda.js (node moda.js), I get only

undefined


as the console output.

What am I doing wrong here?

Thanks so much!

Answer

joe.getresponse() doesn't have an explicit return, thus it has an implicit return undefined;

That's why you are seeing undefined in your console output.

The reason is a bit complicated, and fundamental to javascript programming, but it has to do with Callbacks, and asynchronous execution of javascript.

With this line here, you are actually adding an anonymous function as a callback. That function doesn't actually get executed until it is invoked (typically in response to an event).

  request.on('response', function(response) {
    return(response);
});

So while you are returning the response, the scope of that return is not inside the getresponse() outer function, but instead inside the response event emitter.

Instead, what you want is a pattern along these lines.

main.js

var apiai = require('apiai');
var app3 = apiai(<token>);

exports.getresponse = function(inputstring,callback){
  var request = app3.textRequest(inputstring, {'sessionId': 123456});
  request.on('response', function(response) {
    callback(null,response);
});
  request.on('error', function(error) {
    callback(error,null);
});
  request.end();
};

moda.js

var express = require("express");
var app = express();
var joe = require('./main.js');
joe.getresponse('jacket', function(error,response) {
     if(error) { console.error(error); }
     console.log(response);
 });
app.listen(3000);

Instead of returning the response value, I am invoking a caller supplied callback, which then handles the response (calls console.log).

Comments