Technical Articles
Setting up and consuming APIs from Amazon Alexa via SAP API Management
In this blog post, I will illustrate how to use SAP API Management to access and manage APIs of your systems. Using a simple example application hosted on Cloud Platform, I will demonstrate the basics of API Management and how to leverage its advantages. For that, we will create a simple AWS-hosted Alexa skill, although here anything that can run code and has access to the internet should work just as fine. This serves the purpose of creating a simple sandbox environment, which we can use to explore the basics.
In the context of this blog post, we will mainly be working with two SAP environments: the API Portal and the Developer Portal. The API Portal is the place where you will design, create and configure APIs to your backend or third party systems. Once you created APIs, you can publish sets of one or more APIs as products. In order for developers to consume APIs, products can be subscribed to in the Developer Portal. This way, developers will automatically be assigned things such as API keys and can thus consume previously configured APIs.
Prerequisites
You will need the following:
- An Amazon developer account on Amazon’s developer website
- An active SAP Cloud Platform with API Management subscription enabled
- A system with an exposed API that can be accessed remotely
- The quickest way to get access to such a system is probably by following Marius Obert’s tiny CAP project guide or if you are really short on time simply downloading & deploying the tinyCAP with
cf push tinyCAP
(just make sure you are in the right folder and don’t waste half a day trying to figure out what’s going on).
- The quickest way to get access to such a system is probably by following Marius Obert’s tiny CAP project guide or if you are really short on time simply downloading & deploying the tinyCAP with
- Cloud Foundry CLI
- Node.js and npm and some basic understanding of JavaScript (Sorry, Max)
With that, all the necessary prerequisites should be fulfilled.
Configuring SAP API Management
Setting up the API Provider
First, we will configure an API Provider for the tinyCAP app you set up as part of the prerequisites. On the API Portal navigate to Configure. You will see an overview of your API Providers like this, although if this is your first time using the API Portal, no API Providers will be listed.
Property | Value |
---|---|
Type | Internet |
Host | (your application host) |
Port | 443 |
Use SSL | true |
Trust Store | (leave empty) |
Key Store Certificate | (leave empty) |
If you don’t know the host of your application you can use the Cloud Foundry CLI and run the cf apps
command, which will display an overview of all your deployed apps and their hosts.
Now you should be left with a similar setup to this, just with a different host.
All that’s left to do is configuring the Path Prefix under Catalog Service Settings. If you already played around a little with the tinyCAP app, you will know that a catalogue of all available recourses can be accessed under https://YOUR-APPLICATION-URL/my
. For now, we will enter
Property | Value |
---|---|
Path Prefix | /my |
Service Collection URL | (leave empty) |
Trust All | false |
Authentication Type | None |
To check whether your configuration works click on the URL provided under Catalog URL which should take you straight to an overview of all available recourses of your tinyCAP app in JSON format. You can save and test your Connection now.
Setting up the API
To expose our previously configured API Provider we now need to create an API. On the API Portal navigate to Develop. Once again if this is your first time working with the API Portal no APIs will be listed here.
Click on Create. You will be prompted with a pop-up requiring you to fill out all the necessary details to set up your API. Fill out the required fields as shown below.
Property | Value |
---|---|
Select | API Provider |
API Provider | demo |
Link API Provider | true |
URL | /my |
Name | demo |
Title | First API |
Description | First API using demo API Provider |
Host Alias | (choose one of the options) |
API Base Path | /demo |
Service Type | OData |
The Host Alias and API Base Path will determine the URL through which the API can be accessed. The Host Alias should be filled out automatically, as for the Base Path just enter something simple like /demo
. Make sure to save and deploy your API before continuing.
To test whether the setup of your API has been successful, click on the API you just created and open the API Proxy URL in your web browser. It should display the same data as the Catalog URL from the last step.
Working with the API
We are almost done with the API part of this blog post. Why almost? We already showed that we can access the data in our web browser through the API we created. To demonstrate the last thing that is preventing us from simply making an HTTP GET, we will set up a simple node application like this:
/**
* Test APIs using Axios requests
*/
const axios = require('axios');
(async function () {
const baseURL = "";
let output;
try {
// Get resources from API
const response = await axios.get(baseURL);
// Parse data into readable string
output = `Available resources are: ${response.data.value.map(entity => entity.name).join(", ")}.`;
} catch(e) {
// Error handling
console.error(e.toJSON().stack);
output = "An error occurred";
}
console.log(output);
})();
Note that we make use of the Axios npm package, so make sure to run npm init
and npm install axios
. First, we will need to set the URL we want to make a request to. To check if our code is working, we will first send a request to the tinyCAP app directly, without using API Management. For me, that means setting
const baseURL = "https://tinycap-impressive-pangolin-mg.cfapps.eu10.hana.ondemand.com/my";
Running your program using node should output the same data you can see when opening the URL in your web browser. Great, so that works! Now let’s try the same thing with the API we set up. Set baseURL
to whatever you configured in the previous step. For me that is
const baseURL = "https://devrelations.test.apimanagement.eu20.hana.ondemand.com/demo";
Running the program now will surprisingly result in an SSL Error Unable to verify first certificate
. Looking for a solution online suggests adding appropriate root certificates via the npm ssl-root-cas
package, the solution, however, isn’t quite as simple. To get the request working we manually need to add the PEM chain to node. In Firefox open the URL of your API and hit enter. Click on the small lock icon to the left of the URL bar and navigate to Connection Secure > Show connection Details > More Information. Under Security / Website Identity, click on View Certificate. Under Miscellaneous you can download the PEM (chain).
Alternatively, you can download the .pem file here.
Save it in the same folder your node project is in. To add the PEM chain to our project, we will update our code to look like the following:
/**
* Test APIs using Axios requests
*/
const axios = require('axios');
// Add PEM chain
require('ssl-root-cas').create().addFile("cert.pem");
(async function () {
const baseURL = "";
let output;
try {
// Get resources from API and format as readable string
const response = await axios.get(baseURL);
output = `Available resources are: ${response.data.value.map(entity => entity.name).join(", ")}.`;
} catch(e) {
// Error handling
console.error(e.toJSON().stack);
output = "An error occurred";
}
console.log(output);
})();
If you copy + paste this code make sure to adjust the file name baseURL accordingly. If we run this, our program now we will see the same data we can see in our web browser.
If you prefer using Postman, you can also add the .pem file to Postman by navigating to File > Settings > Certificates.
Also, don’t forget to run npm install ssl-root-cas
Alexa Skill
First create a new skill on the alexa developer console. Enter a Skill name of you liking and choose whatever flavour of English you prefer. Choose “Custom” as your model and “Alexa-Hosted (Node.js)” as the backend hosting method, so we can apply what we learned earlier directly to our skill. If prompted whether you want to add a template to your skill, choose the “Hello World” template. Create your skill, this might take a while.
On the left side, under the Build tab, navigate to Custom > Invocation and choose a Skill invocation name. I will be using “demo two” since I was too lazy to delete the first one. Now navigate to Custom > Intents. Here you should see a list of a few Amazon default Intents, as well a template intent (e.g. HelloWorldIntent) if you chose to add a template to your skill while creating it. Click on + Add Intent. Enter “GetApiDataIntent” as your Intent name and create your custom intent.
Ever wondered how to convert abbreviations consisting of multiple upper case characters into a camel case name (“API” or “Api”)? There are some general guidelines by Microsoft.
As a next step, we need to enter sample utterances, which describe what the user might say to invoke the intent we just created. Since we want to access data, we will go with something like “show me my data” and “show me api data”. Of course, you are free to choose additional or different utterances. Just make sure you end up calling the correct intent(s), going with something too simple such as “show me data” might result in some default Amazon intents being triggered instead of yours. Make sure to save and build your model.
Now we will switch over to the code tab and add some custom code to make the intent behave. First, we need to add our new intent. Copy and paste this code snippet into the index.js
file. Also, make sure to export the handler at the bottom of the file.
const GetApiDataIntentHandler = {
// Check whether handler can handle request
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetApiDataIntent';
},
// Handle request, this is where the magic happens
handle(handlerInput) {
// Define alexa speech output
const speakOutput = 'Inside API Data Intent';
return handlerInput.responseBuilder
.speak(speakOutput)
.getResponse();
}
};
Replace exports.handler = ...
at the bottom of the file with:
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
HelloWorldIntentHandler,
GetApiDataIntentHandler, // Export your own handler
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler, // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers
)
.addErrorHandlers(
ErrorHandler,
)
.lambda();
Save and deploy your code. Switch to the Test tab to check whether everything is working up until now. You might need to switch to development mode to enable testing.
Great! Now let’s add some functionality to our intent. Since we need the axios and ssl-root-cas npm packages we will add them to our skill’s dependencies in the package.json
file.
"axios": "^0.19.2",
"ssl-root-cas": "^1.3.1"
Upon saving & deploying our skill, all required dependencies from package.json
will automatically be installed.
And now: certificates. In the lambda folder create a new file called cert.pem
and copy & paste the content of your previously downloaded certificate chain into it. Switch back to index.js
and add the following to the top of the file:
const axios = require('axios');
require('ssl-root-cas').create().addFile("cert.pem");
Replace the handle
function of the getApiDataIntentHandler
with:
async handle(handlerInput) {
const baseURL = "https://devrelations.test.apimanagement.eu20.hana.ondemand.com/demo";
let output;
try {
// Get resources from API
const response = await axios.get(baseURL);
// Format data as readable string
output = `Available resources are: ${response.data.value.map(entity => entity.name).join(", ")}.`;
} catch(e) {
// Error handling
console.error(e.toJSON().stack);
output = "An error occurred";
}
return handlerInput.responseBuilder
.speak(output)
.getResponse();
}
Notice the async
keyword for the handle
function. Save and deploy your changes. Now, testing our skill should result in a nicely formatted output of available resources, and indeed that is the case.
Let’s recap
We now have an openly available API to an application running on SCP and an Amazon Alexa Skill that accesses this API.
However, to truly leverage the advantages of SAP API Management, we will need to introduce some further concepts, such as policies and basic authentication, since we don’t want our data to be available to anyone. As of now, the only thing our API and API Provider do, is simple request/response forwarding.
You can download all the code I used to run my Alexa skill in this repo. If you want to use this code feel free to import it into your environment, make sure to adjust any names/strings to your needs.
Great Blog! Thank you very much Benno!
Great in-depth information ; have added this blog to https://blogs.sap.com/2016/03/03/sap-api-management-overview-getting-started as an interesting use case 🙂