Skip to Content
Technical Articles
Author's profile photo Piotr Tesny

HERE Location Services with SAP API Management and Kyma functions

Seamlessly integrate location intelligence into SAP LOBs with SAP API Management and Kyma functions

The task here is to implement HERE Location Services with SAP API Management and Kyma functions

HERE Location Services APIs are available on SAP API Business Hub.

With SAP APIM one can copy HERE APIs directly from the API Business Hub and create her/his own managed versions of HERE APIs endpoints within the SAP integration suite framework.

Pre-requisites:

  • Access to HERE Developer account. You can sign up for a free account plan (fremium) as well. Please refer to HERE Location Services documentation for details.
  • SAP BTP sub-account with SAP Integration Suite subscription provisioned with access to SAP API Management portal.
  • SAP API Management is part of SAP Integration Suite and is available with SAP BTP trial account.
Disclaimer:

  • This is not a tutorial. Working knowledge of or at least exposure to OAuth1.0a (and OAuth2.0) security concepts as well as being acquainted with SAP API Management and Kyma runtime are assumed across this blog.
  • For security reasons:
    • the apiKey authentication method will not be used.
    • a digitally signed JWT token will be generated in the backend and implemented as a Kyma function.
  • Please note all the code snippets below are provided “as is”.
  • All the x509 certificates, bearer access and/or refresh tokens and the likes have been redacted.
  • Images/data in this blog post is from SAP internal sandbox, sample data, or demo systems. Any resemblance to real data is purely coincidental.
  • Access to some online resources referenced in this blog may be subject to a contractual relationship with SAP and a S-user login may be required.

Putting it all together

STEP HOW
  • Have access to a HERE developer account.
  • Generate REST application credentials to be used with HERE Location Services REST APIs.
  • These credentials will be used to generate a JWT token with the OAuth1.0a style digital signature (HMAC-SHA256)

 

  • Goto APIM portal to discover the HERE Location Services API package on API Business Hub.
  • There, you will discover, is a number of artifacts (=REST APIs) available. Please explore them thoroughly and select the ones you need.

 

  • For instance, let’s look up the Weather service API.
  • Each API offers a vignette with an ample description of the service with the links to documentation.
  • Copy the API (there is a copy button in the upper right hand side corner of the previous screen).
  • We keep the default service host, so apart from pressing the OK button there is nothing else to do.
  • Deploy the API.
  • It’s almost ready to be used. But as said, as we do not want to use the apiKey but the consumer JWT token instead thus we need to import some additional security policy template to make it happen.
  • Discover the security policies templates.
  • Type policies in Discovery search box and locate a suitable policy, for instance BTP Connectivity policy.
  • Copy the policy “as is” so you can apply it to your own API packages
  • Back to the Weather API.
  • Apply the security policy template using the integrated policy editor
  • Adjust the service call-out policy; (cf. appendix for details)
  • the rest of the policy template is intact.
  • Save, redeploy and start using the Weather API
  • Repeat the same steps for all other APIs from the HERE Location Services package, for instance:

 

For instance let’s get a seven days weather forecast for New York:

https://<APIM domain>.hana.ondemand.com/theta/weather/1.0/report.json?product=forecast_7days_simple&name=new%20york

{
  "dailyForecasts": {
    "forecastLocation": {
      "forecast": [
        {
          "daylight": "D",
          "description": "Sunny. Cool.",
          "skyInfo": "1",
          "skyDescription": "Sunny",
          "temperatureDesc": "Cool",
          "comfort": "11.64",
          "highTemperature": "14.00",
          "lowTemperature": "1.60",
          "humidity": "69",
          "dewPoint": "6.81",
          "precipitationProbability": "1",
          "precipitationDesc": "",
          "rainFall": "*",
          "snowFall": "*",
          "airInfo": "*",
          "airDescription": "",
          "windSpeed": "8.28",
          "windDirection": "270",
          "windDesc": "West",
          "windDescShort": "W",
          "beaufortScale": "2",
          "beaufortDescription": "Light breeze",
          "uvIndex": "0",
          "uvDesc": "Minimal",
          "barometerPressure": "1022.58",
          "icon": "1",
          "iconName": "sunny",
          "iconLink": "https://weather.ls.hereapi.com/static/weather/icon/1.png",
          "dayOfWeek": "2",
          "weekday": "Monday",
          "utcTime": "2021-11-08T00:00:00.000-05:00"
        },
        {
...............(truncated)...................................
        }
      ],
      "country": "United States",
      "state": "New York",
      "city": "New York",
      "latitude": 43.00035,
      "longitude": -75.4999,
      "distance": 0,
      "timezone": -5
    }
  },
  "feedCreation": "2021-11-08T21:02:07.902Z",
  "metric": true
}

 

and the map image:

https://<APIM domain>.hana.ondemand.com/theta/mia/1.6/mapview?ci=New%20York&co=USA&h=600&q=85&w=800

 

Conclusion

I hope you have enjoyed the demo of HERE Location Services.

After I have worked out all the steps APIM allowed me to cut the development time to merely minutes (for each new API service that I wanted to bring to life).

The most complex bit was to create a signed user JWT bearer access token that needs to be passed in the Authorization header of each of HERE Location Service API calls. Initially I wanted to implement the token generation entirely within APIM  but eventually I decided to offload this task to a backend kyma function (cf. appendix below).

The APIM policy takes care of the bearer access token caching and will invalidate it every hour (even if the token itself is valid for 24 hours). Furthermore,  the APIM managed API endpoints can be packed into a product and protected with Oauth2.0 access token if that was required.

Last but not least, because HERE Location Services APIs are being called via a so-called API proxy the Authorization header with the bearer access token is nowhere to be seen.

HERE Location Services are now ready to use with the likes of SAP WorkZone, Launchpad Service, SAP Appgyver or in any bespoke HTML5 application…

 


Appendix

a. The Kyma nodejs backend function to generate the user JWT token

//----------------------------------------------------------------------------------------
const axios = require('axios')
const qs = require('qs')
const OAuth = require('oauth-1.0a') // https://github.com/ddo/oauth-1.0a
const crypto = require('crypto') // https://nodejs.org/en/knowledge/cryptography/how-to-use-crypto-module/


//----------------------------------------------------------------------------------------
//
function hash_function_sha256(base_string, key) {
    return crypto
        .createHmac('sha256', key)
        .update(base_string)
        .digest('base64')
}

//----------------------------------------------------------------------------------------
// https://developer.here.com/documentation/identity-access-management/dev_guide/topics/sdk.html
// Token request function
//
async function generateHEREToken(event) {
    // #1 Initialize OAuth with your HERE OAuth credentials from your HERE project space
    const oauth = OAuth({
        consumer: {
            key: '<Access key>', //Access key
            secret: '<Secret key>', //Secret key
        },
        signature_method: 'HMAC-SHA256',
        hash_function: hash_function_sha256,
    });

// https://stackoverflow.com/questions/61534012/here-map-api-request-token-with-nodejs

    // #2 Building the request object.
    const request_data = {
        url: 'https://account.api.here.com/oauth2/token',
        method: 'POST',
        data: { grant_type: 'client_credentials' }
    };

    const headers = oauth.toHeader(oauth.authorize(request_data));
    console.log (headers);

    let documents;
   
    // #3 Sending the request to get the access token

  try {
    const response = await axios.post(request_data.url,qs.stringify(request_data.data),{ withCredentials: true, headers: {'Authorization': headers.Authorization } });
    
    console.log(JSON.stringify(response.data, null, 2));
    console.log(response.status);

    return response.data; 

  }
  catch(error) {
      documents = JSON.stringify(error, null, 2);
      console.log(error);
  };
  
  return documents;
}
  • here goes the entry point of a kyma serverless function
module.exports = { 
  main: async function (event, context) {

    switch (event.extensions.request.path) {
      case '/here_token2': {
        return generateHEREToken(event);
      }
    }
  }
}

Last but not least. Here goes the function’s response payload:

{
    "access_token": "eyJhbGciOiJSUzUxMiIsImN0eSI6IkpXVCIsImlzcyI6IkhFUkUiLCJhaWQiOiJkanZuR3BOWHpiRGhLZHY3bnR5eSIsImlh
.................................(truncated)..................................................
YKl14kxe425T4HMhcBopWpTJWU9us5TvImzUBDTzkcTd_G8dyQ",
    "token_type": "bearer",
    "expires_in": 86399
}

As the above function call will be called from APIM service callout policy (cf code snippet below), it will need to be exposed to the public internet via an API rule kyma mechanism.

Good to know:

  • kyma serveless functions are intrinsic to current SAP Kyma runtime offering thus there is no separate charge for kyma functions invocations.

 

b. The APIM service callout policy

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" xmlns="http://www.sap.com/apimgmt">
    <Request clearPayload="true">
        <Set>
           <Verb>GET</Verb>
        </Set>
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </Request>
    <Response>sapapim.tokenresponse</Response>
    <Timeout>30000</Timeout>
    <HTTPTargetConnection>
        <URL>https://<API RULE>.kyma.shoot.live.k8s-hana.ondemand.com/here_token2</URL>
    </HTTPTargetConnection>
</ServiceCallout>

 

 


 

Additional resources

OAuth 1.0a Request Authorization | Github

Creating OAuth 1.0 Signature with SCP API Portal | SAP Blogs

OAuth 1.0a Authorization Tutorial | SAP Jam Collaboration Developer Guide | SAP Help

Welcome to SAP API Business Hub Community for API Recipes | Githhub


Developer resources:

  • https://developer.aliyun.com/mirror/npm/package/axios-oauth-1.0a
  • https://stackoverflow.com/questions/56398985/oauth1-0-header-in-node-js
  • https://stackoverflow.com/questions/59500611/here-rest-api-error-signature-mismatch-authorization-signature-or-client-cred
  • https://stackoverflow.com/questions/55557557/axios-post-results-in-bad-request-grant-typeclient-credentials

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.