Skip to Content
Technical Articles
Author's profile photo Benno Grimm

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:

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.

API%20Portal%3A%20Configure

To create a new API Provider, which will act as a middle layer between our tinyCAP app and our Alexa skill, click on Create. You will first be asked to provide a name, “demo” and an (optional) description, for which you can choose whatever you like. Once that is done advance to Connection, where the interesting bits of setting up the API Provider happen. Enter the following attributes as your connection settings:

Property Value
Type Internet
Host (your application host)
Port 443
Use SSL true
Trust Store (leave empty)
Key Store Certificate (leave empty)

API%20Provider%3A%20Connection

If you don’t know the host of your application you can use the Cloud Foundry CLI and run the cf appscommand, 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.

API%20Provider%3A%20Catalogue%20Settings

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.

API%20Portal%3A%20Develop

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.

API%20Portal%3A%20Create%20API%20%281/2%29

API%20Portal%3A%20Create%20API%20%282/2%29

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.

Alexa%3A%20Create%20Skill

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.

Alexa%3A%20Sample%20utterances

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.

Further reading

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Anton Ochel
      Anton Ochel

      Great Blog! Thank you very much Benno!

      Author's profile photo Elijah Martinez
      Elijah Martinez

      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 🙂