0

I have to be missing something really simple here, but here goes.

I am just now starting to learn Alexa development, and found the alexa-app module which seems to make Alexa programming really straight-forward - except for this networking issue I'm running into.

I'm walking through the sample app provided by the team called AirportInfo. The code for the problem area is below:

var faaHelper = new FAADataHelper();
faaHelper.requestAirportStatus(airportCode).then(function(airportStatus) {
    var goodMessage = faaHelper.formatAirportStatus(airportStatus);
    console.log(goodMessage);
    res.say(goodMessage).send();
}).catch(function(err) {
    console.log(err.statusCode);
    var prompt = 'I didn\'t have data for an airport code of ' + airportCode;
    console.log(prompt);
    res.say(prompt).reprompt(reprompt).shouldEndSession(false).send();
});
return false;

which in turns calls these functions:

FAADataHelper.prototype.requestAirportStatus = function(airportCode) {
    return this.getAirportStatus(airportCode).then(
        function(response) {
            console.log('success - received airport info for ' + airportCode);
            return response.body;
        }
    );
};
FAADataHelper.prototype.getAirportStatus = function(airportCode) {
    var options = {
        method: 'GET',
        uri: ENDPOINT + airportCode,
        resolveWithFullResponse: true,
        json: true
    };
    return rp(options);
};

This looks good to me, but when the code runs, the main alexa-app "request" that controls when responses are sent back to the device is returning earlier than expected. Instead of a full response payload with the expected weather information for the selected airport, the response is sent back immediately after the return rp(options) call is made. The code that executes in the .then() block in the first code sample runs after the skill has already sent what amounts to an empty response back to Alexa. This actually crashes Alexa as she says some kind of cryptic message about an error with the skill.

Here's my server.js code:

var AlexaAppServer = require("../index.js");
AlexaAppServer.start({
    server_root: './',
    port: 8080,
    debug: true,
    // Use preRequest to load user data on each request and add it to the request json.
    // In reality, this data would come from a db or files, etc.
    preRequest: function(json, req, res) {
        console.log("preRequest fired");
        json.userDetails = { "name": "Bob Smith" };
    },
    // Add a dummy attribute to the response
    postRequest: function(json, req, res) {
        // look for this output in the log below
        console.log("postRequest fired");
        json.dummy = "text";
    }
});

and here's the debug log showing this condition I'm describing:

preRequest fired
REQUEST { method: 'GET',
  uri: 'http://services.faa.gov/airport/status/dfw',
  resolveWithFullResponse: true,
  json: true,
  simple: false,
  callback: [Function: RP$callback],
  transform: undefined,
  transform2xxOnly: false }
postRequest fired
REQUEST make request http://services.faa.gov/airport/status/dfw
REQUEST onRequestResponse http://services.faa.gov/airport/status/dfw 200 { date: 'Fri, 24 Mar 2017 05:09:41 GMT',
  server: 'Apache',

  ...

  'access-control-allow-origin': '*',
  'access-control-allow-methods': 'GET, HEAD, OPTIONS',
  'version-requested': 'Any',
  connection: 'close',
  'transfer-encoding': 'chunked',
  'content-type': 'application/json;charset=UTF-8' }
REQUEST reading response's body

...

REQUEST end event http://services.faa.gov/airport/status/dfw
REQUEST has body http://services.faa.gov/airport/status/dfw 517
REQUEST emitting complete http://services.faa.gov/airport/status/dfw
success - received airport info for dfw

Notice where preRequest Fired and postRequest Fired show up relative to success - received airport info for dfw. Any ideas what I'm doing wrong? Something mis-configured in my Node environment, or perhaps a bad dependency version? I'm suspicious because it fails in my debugger (VS Code) from the Node command prompt, and from Lambda just the same.

LINK TO FULL SOURCE CODE: https://github.com/bignerdranch/alexa-airportinfo

Chris Koenig
  • 2,736
  • 18
  • 17

1 Answers1

4

I don't understand everything about Promises with regard to Alexa, but I did get this figured out. From the date of your question, there are newer versions of alexa-app-server (3.0.1) and alexa-app (4.0.0) available. I recently developed a skill using these versions. alexa-app 2, the version mentioned in alexa-airportinfo, doesn't work with the latest alexa-app-server.

So, first thing to do is to use the latest alexa-app in your code. Then, realize that by virtue of using request-promise in FAADataHelper, the code is returning a Promise back to index.js. For this to work you need to return that Promise, instead of the false at the end of the function.

To sum up, I got the latest alexa-app-server, changed the alexa-app version in the airportinfo to the latest, and ran it, getting the same result you did - the response comes back before the rp requests are done. When I changed the code to below, I got the desired result - the requests were done, then the response finished with the speech in.

app.intent('airportinfo', {
  'slots': {
    'AIRPORTCODE': 'FAACODES'
  },
  'utterances': ['{|flight|airport} {|delay|status} {|info} {|for} {-|AIRPORTCODE}']
},
  function(req, res) {
    //get the slot
    var airportCode = req.slot('AIRPORTCODE');
    var reprompt = 'Tell me an airport code to get delay information.';
    if (_.isEmpty(airportCode)) {
      var prompt = 'I didn\'t hear an airport code. Tell me an airport code.';
      res.say(prompt).reprompt(reprompt).shouldEndSession(false);
      return true;
    } else {
      var faaHelper = new FAADataHelper();
      return faaHelper.requestAirportStatus(airportCode).then(function(airportStatus) {
        console.log(airportStatus);
        res.say(faaHelper.formatAirportStatus(airportStatus)).send();
      }).catch(function(err) {
        console.log(err.statusCode);
        var prompt = 'I didn\'t have data for an airport code of ' + airportCode;
         //https://github.com/matt-kruse/alexa-app/blob/master/index.js#L171
        res.say(prompt).reprompt(reprompt).shouldEndSession(false).send();
      });
      // return false;
    }
  }
);
rr_cook
  • 136
  • 4
  • Thanks - this was, in fact, the issue. I was inadvertently using an old version of the app server that was causing all my issues. Appreciate the help! – Chris Koenig Jun 30 '17 at 16:25