Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
nidhi_sawhney
Advisor
Advisor

Introduction


Do you want to find road distance and time between 2 locations with current traffic conditions using BTP Services?

In this blog post we will walk through quick and easy low-code steps to use the capabilities provided by SAP Kyma Serverless Functions.We will tackle the common but frequently occurring problem of finding the road distance and times to go from one place to another depending on road and traffic conditions. For this SAP HANA Spatial Services provide extensive capabilities

For details on use of Kyma functions refer to SAP Help Documentation for Kyma Functions. I will use python as the programming language for all code snippets provided here. Alternatively Node.js could also be used in Kyma Functions.

The steps below describe the creation of an API to provide driving distance and time between 2 address  locations. For this purpose we will use the SAP HANA Spatial Services. For detailed reference on these services please refer to SAP Help Documentation for SAP HANA Spatial Services and other helpful details are provided here SAP Discovery Mission.

The approach described here takes away the hassle of managing high availability infrastructure for providing services and that tooo with just a few lines of code. It utilizes the cloud-based offering running on powerful infra-structure managed by SAP for spatial services with a scalable runtime.

Pre-requistites


To go through the the steps you would need to ensure you already have the following:

  1. Setup BTP Account with HANA Spatial Services as described here SAP HANA Spatial Service on BTP. Alternatively you can create the Service Instance and Service Binding in Kyma cockpit. This is advisable as then you can use the service credentials from the binding instead of coding it in the function. In this case the service is created in the same subaccount as the Kyma cluster and you need to ensure the subaccount has entitlement to create the service.

  2. Setup BTP Account with SAP Kyma runtime as described here Create Kyma Environment on BTP


Setup HANA Spatial Services in Kyma Cockpit (Optional)


If you do not already have a HANA Spatial Service instance you can create one in Kyma Cockpit.

Go to your chosen namespace in Kyma where you plan to develop the functionality, navigate to Service Management Section.

1. Add BTP Service Instance


Go to BTP Service Instances and press Create and you will get the following form


BTP Service Instance Creation on Kyma


 

You can choose the Plan Name to be standard or lite depending on the entitlement of the spatial service to the BTP subaccount where the Kyma clusters is provisioned. The Offering Name has to be spatialservices. The Name is of your own choice.

Once the service is created you will see the following


HANA Spatial Services Instance on Kyma



2. Add BTP Service Binding


Next step is to add a service binding to the above spatial service instance. This step creates the required credentials needed to get OAuth token for using the HANA Spatial Services.

Under Service Management now go to BTP Service Bindings and press Create. In the dropdown of the Service Instance Name you will see the existing service instances. Choose the one created in step 1 above, in the example above we called hss-instance



Creating HANA Spatial Service Binding on Kyma


 

This results in the following binding to be provisioned


HANA Spatial Service Binding Provisioned on Kyma


 

If you click on the binding name above, you will see that this creates an associated Secret with the same name, in our example hss-binding.


HANA Spatial Service Binding


You can go look at the hss-binding secret and decode it. We will use the uaa  which has the url, clientid,clientsecret fields of this secret in the step to get OAuth token below. We will use the uri field of the secret to get HANA Spatial Service url for geocoding and route.


Kyma Secret for HANA Spatial Service


In steps below we will access the above secret properties in the Kyma function.

Create Python Functions to calculate distance between 2 locations


SAP HANA Spatial Services provide many advanced capabilities for geocoding, routing and mapping. For the example we will focus on answering the question "How to find the distance and time to go from one address to another using a car?" Also the service should gracefully return incase it is not able to map either of the origin or destination addresses.

Since the user-input is provided as addresses, first step is to have a function to get the latitude and longitude of the addresses

For this we will use the POST /geocoding/v1/geocode API followed by the POST /routing/v1/route API. Now using these APIs require the generation of OAuth token. To generate this token you would need 3 things from the HANA Spatial Service instance created in step 1 of the pre-requisites above.

1. Get OAuth Token


Option 1


If you want to use an existing HANA Spatial Services without binding to your function. However, it is advisable to follow the steps to use the binding option so you do not have hard-coded values for secret parameters as described in Option 2.


From the BTP Cockpit access your service key and note the url, clientid and clientsecret

 


Service Key on BTP Cockpit


 


Access Details from Service Key


 

Here is the code in python to use the above credentials to get the OAuth token
import requests
import json

def getToken():

url = <url from service key>
params = { "grant_type": "client_credentials" }

auth = (<clientid from service key>,<clientsecret from service key>)
response = requests.post(url, data=params,auth=auth)

d = json.loads(response.text)
return d['access_token']

Option 2


In this case we will use the secret created in step Setup HANA Spatial Services in Kyma Cockpit above. When you add a function in Kyma you also have the option to add associated Environment Variables. Since we already created a service binding and associated secret, you can choose to create an Environment variable to reference these in your code


Environment Variable for UAA


We will create 2 environment variables using the secret hss-binding (the name of our binding created before, if you chose a different name you will see it in the drop down above for Creating Secret Value. The  variables are for uaa and uri fields from secret, here I called them hssuri and hssuaa.


Environment Variables for Accessing Secret


Here is code to get the OAuth token which uses the environment variables instead of coding it in the function
import requests
import json
import os

def getToken():

hssuaa = os.environ.get('hssuaa') #replace with environment variable for uaa if different name
if hssuaa:
hssuaa = json.loads(hssuaa)
url = hssuaa['url'] + '/oauth/token'
params = { "grant_type": "client_credentials"}
auth = (hssuaa['clientid'],hssuaa['clientsecret'])

response = requests.post(url, data=params,auth=auth)

d = json.loads(response.text)
return d['access_token']
else:
raise Exception("HANA Spatial Credentials missing")

2. Get Geo-code from address


Here is python code to use the HANA Spatial Services for geocoding to get latitude and longitude. The url in the code below needs to be replaced by the uri from the service key and the token is obtained by the function above
def getCoord(address,token):
url = <uri from serice key>/geocoding/v1/geocode #If using Option 1 Spatial Service
url = os.environ.get('hssuri')+'/geocoding/v1/geocode' #If using Option 2 with Service Binding
headersAPI = {
'accept': 'application/json',
'content-type': 'application/json',
'Authorization': 'Bearer '+ token,
}
body = {
"credentials": {
"provider": "Here",
"api_key": "SAP-KEY"
},
"addresses": [address]
}
response = requests.post(url, json=body,headers=headersAPI)
return json.loads(response.text)['features'][0]['geometry']['coordinates']

The geocode service also returns useful information like matchScore and addressType which can be useful for ambiguous cases where the address match is not perfect.

3. Get the distance and other metrics from HANA Spatial Service


The routing service from HANA Spatial Services requires latitude and longitude that we get from the function above. Here is python code to use the routing service to get distance and time metrics between 2 locations.
def getHSSDistance(from_address,to_address):
token = getToken()
from_coord = getCoord(from_address,token)
if not from_coord:
raise Exception("Unidentiified from address " + from_address)

to_coord = getCoord(to_address,token)
if not to_coord:
raise Exception("Unidentified to address " + to_address)

url = <uri from service key>/routing/v1/route #If using Option 1 for Spatial Service
url = os.environ.get('hssuri')+'/routing/v1/route' #If using Option 2 with Service Binding


body = {
"credentials": {
"provider": "Here",
"api_key": "SAP-KEY"
},
"waypoints": {
"type": "MultiPoint",
"coordinates": [
from_coord,
to_coord
]
},
"vehicleType": "car",
"returnGeometry": False
}

headersAPI = {
'accept': 'application/json',
'content-type': 'application/json',
'Authorization': 'Bearer '+ token,
}

response = requests.post(url, json=body,headers=headersAPI)
data = json.loads(response.text)['properties']
duration = data['duration']/60 ## Converting to minutes
distance = data['distance']/1000 ## Converting to Meters to KM
return distance,duration


As you see we simply chose vehicleType to be car because we are interested in driving distance. There are other parameters which can be useful and by default the traffic information is set to true and the departureTime to now. The detailed list of parameters is here. Also the parameters for the routes can be more complicated as a list of waypoints instead of only an origin and destination as in my example above.

Create Kyma Function to provide API to return distance and time between 2 addresses


Now that we have all the building blocks ready, we are ready to add this function to Kyma and provide an API endpoint which takes 2 addresses and returns the driving distance and time between. This is a detailed step-by-step description by following Kyma documentation for creating Serverless Function

Go to your Kyma dashboard on BTP and choose the namespace you would want to add the service to, for example below I have 3 namespaces and I choose dev


Kyma Dashboard Namespace Selection


In the namespace now go to Functions and create an inline function. I chose Python as the code snippets above are for Python.



Kyma Inline Python Function


 

When you press create you get a "Hello World" sample code from Kyma. We will change the code to add the 3 functions above and a main function which uses it and returns the answer to the API


Kyma Main Function


All the functionality for geocoding and routing is provided by the HANA Spatial Services so we do not need to add any other packages. Incase there are additional packages needed they can be added in the Dependencies section. The format to add packages here is same as in requirements.txt, for example python package name with desired version.

 

Now add an API endpoint so we can call the above function


Kyma API Configuration


 

Creating the API rule is straightforward, you can change the Name as you like and provide a Subdomain which adds a prefix to the host and helps to distinguish this service from others you may create on the Kyma cluster


The advanced options above provide capabilities to scale the endpoint and the underlying compute required. For this usecase we can use the XS as there is not a lot of compute needed and its off-loaded to the HANA Spatial Service. We can add more replicas depending the expected usage of the endpoint and Kyma cluster size.


Kyma Resource Configuration


Once the API is created your function would look like this


Kyma Function with API


The host endpoint above can then be used to test the endpoint

Testing and Debugging the endpoint


You can test the endpoint by providing it a from and to address. To see the print messages in the code you can open the logs from the function logs in Kyma


Kyma Function Logs


 

When you call the API from curl or Postman as in example here, the logs can be seen in the Kyma dashboard


Sample Logs


 

For cases when there are errors in the code either at build time or deploy time, the logs can be checked in the Grafana logs. To see the grafana logs follow the instructions provided here at Setup Grafana for Kyma Metrics and Logs. Some other useful examples for debugging are provided in this blog post Kymas Serverless Python Functions A Short Excursion

 
8 Comments
gregorw
Active Contributor
0 Kudos
Dear Nidhi,

thank you for sharing in the SAP Community. But can you please check how to do the OAuth (not O-Auth) authentication without hardcoding the values in the source code? I think the blog post The new way to consume Service Bindings on Kyma Runtime should guide you.

Best Regards
Gregor
rafael_pacheco
Participant
0 Kudos
Nidhi, this is an extremely useful work. Thank you!
nidhi_sawhney
Advisor
Advisor
Thanks gregor.wolf  for pointing it out. I have now added the option to use service bindings so one does not have to hardcode values but access them from Kyma secret. Since I wanted to keep it friendly for Kyma Cockpit users, the steps are executed in the Kyma Cockpit without the need to edit yaml files.
gregorw
Active Contributor
0 Kudos
Great. I hope you completely remove Option 1.
nidhi_sawhney
Advisor
Advisor
0 Kudos
Yes, I understand, hence recommended Option 2. However Option 1 helps when the service already exists and enables quick testing of Spatial Service functionality outside of Kyma.
fazam
Product and Topic Expert
Product and Topic Expert
0 Kudos
Practical and useful contribution. Greatly appreciated you sharing with us. Thank you!
former_member317091
Discoverer
0 Kudos
Thank you! I like the level of detail. And if there are questions open, you have just the link to further docs. Great!
gregorw
Active Contributor
But you should never keep secrets in source code.