In the previous articles, we have different aspects of developing Alexa skills. We learned how to pass state between intents and sessions.

Sometimes, you may run into a situation when you need to interact with external services. It could be a service to fetch weather information, local news or, you can even set up a private service to interact with IoT devices. Basically, anything you can interact with over HTTP.

Now, let’s learn how we can interact with external APIs from an Alexa skill.

We are going to implement a skill that provides quotes from famous people.

Once we ask Alexa for an inspirational quote, the skill will fetch quotes from an API and tell a random quote back to us.

To begin, I’ll create a boilerplate Hello World skill with the single QuoteIntent.

In the example below, you can see the initial implementation of the intent handler.

const randomArrayElement = (array) =>
  array[Math.floor(Math.random() * array.length)];

const fetchQuotes = () => {
  return new Promise((resolve, reject) => {
    resolve([
      { content: "Quote 1", author: "Author 1" },
      { content: "Quote 2", author: "Author 2" }
    ]);
  })
};

const QuoteIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'QuoteIntent';
  },
  async handle(handlerInput) {
    try {
      const quotes = await fetchQuotes();
      const quote = randomArrayElement(quotes);
      const speechText = `${quote.content} ${quote.author}.`;

      return handlerInput.responseBuilder
        .speak(speechText)
        .withSimpleCard('Inspiration', speechText)
        .getResponse();
    } catch (error) {
      console.error(error);
    }
  },
};

We have an async handler function. Inside the function, we are fetching a list of the quotes. Then we get a random quote from the list and say it to the user.

Our goal is to update the implementation of the fetchQuote() function to fetch data from some sort of API instead of providing us some hardcoded data.

Let’s do that.

There are different ways to make an HTTP call in JavaScript. Some of them are described in this article from the Twilio blog.

For our example, I’ve picked a library called axios. I’ve chosen this library primarily because it is based on Promises.

First, we need to install it as a dependency. Be sure to install it from the directory which contains the source code of the lambda function itself.

→ cd lambda/custom
→ npm install axios --save
→ cd -

Then, at the top of the index.js file, we need to require the library.

const axios = require('axios');

Now, we are ready to reimplement the fetchQuotes() functions to make an API call.

const fetchQuotes = async () => {
  try {
    const { data } = await axios.get(quotesUrl);
    return data;
  } catch (error) {
    console.error('cannot fetch quotes', error);
  }
};

All we do here is make a GET HTTP request to fetch the data from the quotesUrl (we will get to it in a bit). Once we get the data, we return it back.

The quotesUrl constant contains a URL to an external API. In our case, we’re using a JSON file described in the following gist. The gist has a similar function to our initial fetchQuotes() function structure. It contains an array of objects each of which has content key and an author key.

[
  {
    "content": "It does not matter how slowly you go, as long as you do not stop.",
    "author": "Confucius"
  }
]

In order to make it work, we need to define a variable containing the path to the quotes.json file from the gist.

const quotesUrl = 'https://gist.githubusercontent.com/ck3g/44afbba3a80270167cedad37bb8114e3/raw/quotes.json';

After that, we are ready to deploy the skill and test it.

And it works.

The complete example you can find on the GitHub page.

Wrapping up

We can see that making API calls from Alexa skill does not make much difference as API calls in any other JavaScript projects.

Using such a feature in our skills gives a very powerful ability. Now we need to extend the list of the quotes just by updating the API (in our case it’s the gist file).

I am using the gist just for the sake of that example. In the end, it does not matter too much what kind of API do you use, as long as it provides you a data you need.

Of course, it is also possible to make a different kind of API calls. Your skill may collect some data from the user and perform the POST requests to update your services. Or it could be a chain of HTTP requests to fetch the data based on a user’s needs.

See you next time.