Alexa Skill Recipe Update: Call and Get Data from External APIs

Jamie Grossman Sep 17, 2018
Share:
Build Node.js Tips & Tools Tutorial
Blog_Header_Post_Img

In a previous Alexa skill recipe, we shared how you can call HTTP requests to get data from an external API, enabling your skill to fetch meaningful data from a remote source. Since then, we’ve released version two of the Alexa Skills Kit Software Development Kit (SDK) for Node.js. With the new SDK, there are new methods to be aware of for making HTTP calls to external APIs. This post details the process of making external API calls in version two of the SDK.

Whereas you may be familiar with achieving this through callbacks in version one of the SDK, we actually approach this in version two through the use of promises. With version two, you cannot send a response to Alexa through a callback. Below, we elaborate a little further.

Understanding How Version Two Handles Responses

Below, we have an example handler for a response using version two of the SDK:

Copied to clipboard
const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  handle(handlerInput) {
    const speechText = 'Hello World!';

    return handlerInput.responseBuilder
      .speak(speechText)
      .withSimpleCard('Hello World', speechText)
      .getResponse();
  },
};

As shown above, we need to return our object after we have added everything required, so we cannot call another function and rely on a callback (like we would have done in version one). This is because we’ve lost access to that specific scope and we wouldn’t really be returning our object anywhere, except for inside the new scope after the callback has been handled. With that in mind, we need a new approach to understand how to call external APIs in version two the SDK.

Understanding Await, Async, and Promises

Through these types of operators, functions, and objects, we can call external APIs through version two of the SDK without the need of a callback – they are part of Javascript and we are able to make use of them in our Node.js code.

We’ll only touch on these concepts, but to summarise:

  • async: If you async before a function declaration, we are committing that this function will return a promise.
  • await: Only inside async functions, using await will make your code wait until that promise has been settled with a result returned
  • Promise: As shown by the name, this is literally a promise that an object may (or may not) produce a value at some point in the future

So, how do we use these to call external APIs? We are now going to literally halt our code until some other code (in our case, the actual HTTP call) has been completed and resolved. Once complete, we get our data and add it to our Alexa response object.

Example Approach for HTTP Calls in Version Two

1. Again, we initialise the https module which is a default part of Node.js:

Copied to clipboard
var https = require('https');

2. Write a function that process requests and sends back responses from the server via callback (in this case, a Chuck Norris joke API):

Copied to clipboard
function httpGet() {
  return new Promise(((resolve, reject) => {
    var options = {
        host: 'api.icndb.com',
        port: 443,
        path: '/jokes/random',
        method: 'GET',
    };
    
    const request = https.request(options, (response) => {
      response.setEncoding('utf8');
      let returnData = '';

      response.on('data', (chunk) => {
        returnData += chunk;
      });

      response.on('end', () => {
        resolve(JSON.parse(returnData));
      });

      response.on('error', (error) => {
        reject(error);
      });
    });
    request.end();
  }));
}

3. Call the function and respond to the user with the formatted data:

Copied to clipboard
const GetJokeHandler = {
  canHandle(handlerInput) {
    const request = handlerInput.requestEnvelope.request;
    return request.type === 'IntentRequest'
      && request.intent.name === 'GetJokeIntent';
  },
  async handle(handlerInput) {
    const response = await httpGet();
    
    console.log(response);

    return handlerInput.responseBuilder
            .speak("Okay. Here is what I got back from my request. " + response.value.joke)
            .reprompt("What would you like?")
            .getResponse();
  },
};

So as you can see in step 1, we initialize the HTTP module once again – nothing has changed here.

For step 2, you’ll notice that our httpGet function is similar in the sense that it is passing in the relevant options to the call and parsing the data It gets back, but you’ll notice that this is now enclosed inside of a promise. Because of our commitment, we handle our two functions inside of this promise; resolve if everything is successful where we parse our data and send it back, and reject where there is something wrong and we error out.

On to step 3, we create our version two handler and ensure we add async to our handle function because as mentioned before, we are saying that the following code will return a promise at one point. Because of this declaration, we can then add await to out httpGet call, and as mentioned before, this will then halt the code until our external call has completed/resolved. Once we have our data, we the just send it back to the user as normal.

Learn More and Get Started

You can find these concepts and more in the Pet Match sample in the official Alexa Github, and if you haven’t yet checked out the new SDK, see the official repository over here for more info and documentation. Reach out directly to me @jamielliottg, post on the forums, or get in touch with questions about how this works!

Related Content

Make Money by Creating Engaging Skills Customers Love

When you create delightful skills with compelling content, customers win. You can make money through Alexa skills using in-skill purchasing or Amazon Pay for Alexa Skills. You can also make money for eligible skills that drive some of the highest customer engagement with Alexa Developer Rewards. Learn more about how you can make money with Alexa skills.