title: AWS Lambda unable to call external https endpoint
body: <p>We are working on an Alexa skill and it will need to reach out to external REST API's to get data. I'm having a really hard time getting this to work in our lambda function for some reason. I'm also having a hard time determining if the problem is in my node.js code not using callback's correctly or if it's in the VPC settings for my function. Here is my code, I've stripped out the non-essential stuff.</p>
  
  <pre><code>/* eslint-disable  func-names */
  /* eslint quote-props: ["error", "consistent"]*/
  /**
   * This sample demonstrates a simple skill built with the Amazon Alexa Skills
   * nodejs skill development kit.
   * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
   * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
   * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
   **/
  
  'use strict';
  
  const Alexa = require('alexa-sdk');
  
  const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).
  
  const https = require('https');
  
  const handlers = {
      'LaunchRequest': function () {
          this.emit('GetFact');
      },
      'GetNewFactIntent': function () {
          this.emit('GetFact');
      },
      'maintenanceIntent': function () {
          console.log('inside maintenanceIntent');
  
      var options = {
          host: 'api.forismatic.com',
          path: '/api/1.0/?method=getQuote&amp;lang=en&amp;format=text',
          method: 'GET'
      };
  
      getQuote(options, function (quote){
              if(quote === ''){
                  console.log("No quote");
                  //speechOutput = "Please try again later";
              }
              else{console.log(quote)}
              //self.emit(':tellWithCard', speechOutput, SKILL_NAME, text);
          });
  
          // Create speech output
          // Place holder
          var randomFact = 'Test Fact';
          const speechOutput = randomFact;
          this.emit(':tellWithCard', speechOutput, 'test skill name', randomFact);
      },
      'AMAZON.HelpIntent': function () {
          const speechOutput = this.t('HELP_MESSAGE');
          const reprompt = this.t('HELP_MESSAGE');
          this.emit(':ask', speechOutput, reprompt);
      },
      'AMAZON.CancelIntent': function () {
          this.emit(':tell', this.t('STOP_MESSAGE'));
      },
      'AMAZON.StopIntent': function () {
          this.emit(':tell', this.t('STOP_MESSAGE'));
      },
  };
  
  exports.handler = function (event, context, callback) {
      const alexa = Alexa.handler(event, context);
      alexa.APP_ID = APP_ID;
      // To enable string internationalization (i18n) features, set a resources object.
      //alexa.resources = languageStrings;
      alexa.registerHandlers(handlers);
      alexa.execute();
  };
  
  function getQuote(options, callback){
      var text = '';
      console.log("in getquote");
      https.get(options, function(res) {
          console.error("Got response: " + res.statusCode);
          res.on("data", function(chunk) {
          console.error("BODY: " + chunk);
          text = '' + chunk;
          return callback(text);
      });
      }).on('error', function(e) {
          text = 'error' + e.message;
          console.error("Got error: " + e.message);
  });
  }
  </code></pre>
  
  <p>Now when I invoke the maintenanceIntent this is what I see in the logs.</p>
  
  <pre><code>{"timestamp":1508426249817,"message":"START RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8 Version: $LATEST","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  {"timestamp":1508426250256,"message":"Warning: Application ID is not set","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  {"timestamp":1508426250256,"message":"inside maintenanceIntent","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  {"timestamp":1508426250256,"message":"in getquote","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  {"timestamp":1508426250256,"message":"END RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  {"timestamp":1508426250256,"message":"REPORT RequestId: 9f66123e-b4e0-11e7-baac-1bfb01d2abc8\tDuration: 378.28 ms\tBilled Duration: 400 ms \tMemory Size: 128 MB\tMax Memory Used: 33 MB\t","logStream":"2017/10/19/[$LATEST]0e048ab2fc5441cda8007e4a1963bf02","logGroup":"/aws/lambda/factDemo","requestID":"9f66123e-b4e0-11e7-baac-1bfb01d2abc8"}
  </code></pre>
  
  <p>So I can see it's actually calling the getQuote function. I'm not seeing any errors or success messages at all. I thought maybe I wasn't using callbacks correctly (node isn't my normal development language) but I've actually pulled code straight from an Amazon example on GitHub and I couldn't even get that to work. (This code is very similar to it except it's a little shorter.)</p>
  
  <p>If I strip this down and run it locally through the node, it works fine. </p>
  
  <p>As far as the networking stuff, I followed this guide: <a href="https://gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7" rel="nofollow noreferrer">https://gist.github.com/reggi/dc5f2620b7b4f515e68e46255ac042a7</a> 
  . I've also tried Amazon guides but at this point, I'm not even sure how I would check internet connectivity or if this is even the problem.</p>
  
  <p>Any help to get on the right track would be greatly appreciated!</p>
  
  <p>--EDIT--</p>
  
  <p>I've changed my code as so. This comes straight from the alexa-cookbook at <a href="https://raw.githubusercontent.com/alexa/alexa-cookbook/master/external-calls/httpsGet/src/index.js" rel="nofollow noreferrer">https://raw.githubusercontent.com/alexa/alexa-cookbook/master/external-calls/httpsGet/src/index.js</a></p>
  
  <pre><code>/* eslint-disable  func-names */
  /* eslint quote-props: ["error", "consistent"]*/
  /**
   * This sample demonstrates a simple skill built with the Amazon Alexa Skills
   * nodejs skill development kit.
   * This sample supports multiple lauguages. (en-US, en-GB, de-DE).
   * The Intent Schema, Custom Slots and Sample Utterances for this skill, as well
   * as testing instructions are located at https://github.com/alexa/skill-sample-nodejs-fact
   **/
  
  'use strict';
  
  const Alexa = require('alexa-sdk');
  
  const APP_ID = undefined;  // TODO replace with your app ID (OPTIONAL).
  
  const https = require('https');
  
  const handlers = {
      'LaunchRequest': function () {
          this.emit('GetFact');
      },
      'GetNewFactIntent': function () {
          this.emit('GetFact');
      },
      'maintenanceIntent': function () {
          console.log('inside maintenanceIntent');
  
      var myRequest = 'Florida';
  
      httpsGet(myRequest,  (myResult) =&gt; {
                  console.log("sent     : " + myRequest);
                  console.log("received : " + myResult);
  
                  this.response.speak('The population of ' + myRequest + ' is ' + myResult);
                  this.emit(':responseReady');
  
              }
          );
  
          // Create speech output
          // Place holder
          var randomFact = 'Test Fact';
          const speechOutput = randomFact;
          this.emit(':tellWithCard', speechOutput, 'test skill name', randomFact);
      },
      'AMAZON.HelpIntent': function () {
          const speechOutput = this.t('HELP_MESSAGE');
          const reprompt = this.t('HELP_MESSAGE');
          this.emit(':ask', speechOutput, reprompt);
      },
      'AMAZON.CancelIntent': function () {
          this.emit(':tell', this.t('STOP_MESSAGE'));
      },
      'AMAZON.StopIntent': function () {
          this.emit(':tell', this.t('STOP_MESSAGE'));
      },
  };
  
  exports.handler = function (event, context, callback) {
      console.log("exports handler");
      const alexa = Alexa.handler(event, context);
      alexa.APP_ID = APP_ID;
      // To enable string internationalization (i18n) features, set a resources object.
      //alexa.resources = languageStrings;
      alexa.registerHandlers(handlers);
      alexa.execute();
      console.log("post execute");
  };
  
  function httpsGet(myData, callback) {
  
      // GET is a web service request that is fully defined by a URL string
      // Try GET in your browser:
      // https://cp6gckjt97.execute-api.us-east-1.amazonaws.com/prod/stateresource?usstate=New%20Jersey
  
      console.log("in");
      console.log(myData);
      // Update these options with the details of the web service you would like to call
      var options = {
          host: 'cp6gckjt97.execute-api.us-east-1.amazonaws.com',
          port: 443,
          path: '/prod/stateresource?usstate=' + encodeURIComponent(myData),
          method: 'GET',
  
          // if x509 certs are required:
          // key: fs.readFileSync('certs/my-key.pem'),
          // cert: fs.readFileSync('certs/my-cert.pem')
      };
  
      var req = https.request(options, res =&gt; {
          res.setEncoding('utf8');
          var returnData = "";
          console.log("request");
          res.on('data', chunk =&gt; {
              console.log("data");
              returnData = returnData + chunk;
          });
  
          res.on('end', () =&gt; {
              console.log("end");
              // we have now received the raw return data in the returnData variable.
              // We can see it in the log output via:
              // console.log(JSON.stringify(returnData))
              // we may need to parse through it to extract the needed data
  
              var pop = JSON.parse(returnData).population;
  
              callback(pop);  // this will execute whatever function the caller defined, with one argument
  
          });
  
      });
      console.log("req.end");
      req.end();
  
  }
  </code></pre>
  
  <p>Same idea but slightly different execution of getting the result from the endpoint. This is the log output.</p>
  
  <pre><code>{"timestamp":1508434982754,"message":"START RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f Version: $LATEST","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434982887,"message":"exports handler","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434982887,"message":"Warning: Application ID is not set","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434982887,"message":"inside maintenanceIntent","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434982887,"message":"in","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434982887,"message":"Florida","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434983307,"message":"req.end","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434983309,"message":"post execute","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434983367,"message":"END RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  {"timestamp":1508434983367,"message":"REPORT RequestId: f4a39351-b4f4-11e7-a563-fbf7599fa72f\tDuration: 608.20 ms\tBilled Duration: 700 ms \tMemory Size: 128 MB\tMax Memory Used: 35 MB\t","logStream":"2017/10/19/[$LATEST]3252e394be9b4a229c3a0d042deffbf8","logGroup":"/aws/lambda/factDemo","requestID":"f4a39351-b4f4-11e7-a563-fbf7599fa72f"}
  </code></pre>
  
  <p>I've tried this in the VPC and out of the VPC with the same result.</p>