Most Alexa Skills and Google Actions rely on some sort of external data. Learn how to build a voice app that calls an external API and leverages the modern JavaScript concept async/await.
Watch the video here:
Introduction
With the launch of v2
of the Jovo Framework, we updated the way requests and responses are executed. You can learn more about requests and responses here.
The framework now uses the concept of JavaScript promises: The response back to the voice platform (Amazon Alexa, Google Assistant) is sent out once the handler promise is resolved. This means there are a few things to consider when dealing with asynchronous method calls.
In this tutorial, we are going to build a simple Alexa Skill and Google Action with the Jovo Framework that does an API call and return a response based on the data it receives.
Want to learn more about the basics first?
- async/await tutorial
- Promise tutorial
Making an API Call that Returns a Random Quote
As an example, let's build a voice app that returns a random quote. There is a free Star Wars Quote API that we can use:
This is how the interaction would be like:
Ideally, we would want a quote intent and that calls a getRandomQuote
method:
Why async/await
The problem with API calls is that they are asynchronous, which could lead to a problem when executing the response. For example, if we log the request, response, and the quote. It can look like this:
As you can see, the voice app sends out an empty response without waiting for the API call to be finished. This is because the handler promise gets resolved (all handlers have been executed from start to finish) without waiting for the asynchronous API call.
With async/await, you can make the handler await
asynchronous calls. You also have to add async
to all functions that use await
:
In this tutorial, you can find two options how we can make this work:
Option 1: Using Request Promise
The cleanest way is to let the request
module return a promise right away. There are several packages that offer this functionality:
request-promise
(uses Bluebird Promises)request-promise-native
(uses native Promises)request-promise-any
(uses any-promise Promises)
We are going to use the request-promise-native
package for this:
In the app instantiation section, we can require it like this:
And then use it in the getRandomQuote
method:
Option 2: Using Traditional Request
If you're used to the traditional request
package, you can use this as well:
And initialize it like this:
This won't return a promise, so we need to create a promise from the API response like this:
Next Steps
- Read this post to learn how to migrate your existing code: From Callbacks to Async-Await: A Migration Guide.
- There are also a few considerations when using async/await: How to escape async/await hell
Troubleshooting
If you are doing an intent redirect like this.toIntent
to an intent that is asynchronous, make sure to either await it or add a return
statement: