SAP Business Application Studio has recently broadened its support to encompass Python, as indicated by SAP.
This additional capability facilitates the development of Python-based applications. In this blog post, I'll walk you through how to establish a Python-driven development environment in SAP Business Application Studio. We'll also initiate a project and develop a compact web application, which includes a REST API endpoint that interfaces with the SAP S/4HANA Cloud system to retrieve supplier details via the destination service, thereby pulling the list of suppliers. For a more in-depth understanding of SAP Business Technology Platform (SAP BTP) setup and SAP Business Application Studio setup, consider referencing the E-Bite I co-authored for SAP PRESS. If you're interested in gaining more insights about Python, please consult the provided link.
Introduction
This post serves as a continuation of our previous discussion on the Python RESTful API, where we've delved into the development of RESTful APIs in Python. Here, we'll focus on how to use the OData service of the SAP S/4HANA Cloud system, how to incorporate it into a Python application, and how to expose it through a RESTful API by crafting a wrapper for the OData API of SAP S/4HANA Cloud.
My secondary objective is to guide you in creating a prototype application. This will involve setting up a Python project and configuring a destination to link it to in the SAP S/4HANA Cloud system. The application is aimed to interpret the OData API to acquire a list of suppliers and create a wrapper RESTful API in Python, which will be obtained by consuming supplier data from SAP S/4HANA Cloud.
RESTful APIs are potent resources that facilitate communication between various software applications. In the scope of our tutorial, it will be employed to extract a list of suppliers by creating a wrapper for the pre-existing OData service from the SAP S/4HANA Cloud ES5 demo system. This is to exemplify how we can consume any services from the cloud system and manage the data or services in Python for customization, or to perform any form of data manipulation using the Python programming language.
Join us in exploring the intriguing domain of Python development, where we will set up a development environment and build an application that interacts with RESTful APIs. I am certain that this post will offer essential knowledge and practical experience that will be beneficial for your upcoming Python projects.
Pre-requisite Steps:
- Set up the ES5 demo system as per the mentioned at this link.
- Navigate to the SAP BTP account and create a trial account.
- Set up the SAP Business Application Studio to launch the URL as mentioned in this link.
- Launch the URL in the browser as shown below and click on “dev space creation.”
Now click on the dev space and provide a unique name such as “py_dev”. Select the “Python Tools” from the Additional SAP Extensions; you may select other extensions also based on your requirement and development activity. I selected a couple of other extensions in my tutorial but that is optional. After selection, click on “Create Dev Space” and wait for a few minutes. Refer to the figure below for a preview.
Once the dev space creation state is being shown as “RUNNING,” as shown below, click on it to open the dev space. It may take some time to load.
Once the dev space is launched, navigate to the workspace and create a new “Basic Multitarget Application” by selecting the option “New project from Template” as shown below.
Select “Basic Multitarget Application” and click the start option. On the next screen, provide the project name as “mywebApp” and click on FINISH as shown below.
The reason you create the “Basic Multitarget template” is because you need to create a project with mta.yml, since it will be used to create the MTA-based application. Once the full stack app is developed, you can deploy it to SAP BTP.
SAP S/4HANA Destination Configuration
After you set up the ES5 demo system, configure the destination in the SAP BTP account as mentioned below.
- Navigate to the SAP BTP account.
- Click on sub-account and navigate to the “Connectivity” section in the right panel.
- Expand it and click on the Destinations tab. Configure the destination system as mentioned in this link (step 2).
Development Setup
Now open a terminal/create a folder for “mywebApp” and navigate to this folder using command. Then install the package related to Python as shown below.
> mkdir mywebApp
> cd mywebApp
> npm install python
> python –version // 3.0+ version should be 3+
> npm install pip // python package installer
> pip install flask // python web development package should be 3.0.0
> pip install jsonify
> npm i cfenv
> npm i requests
> pip3 install werkzeug
> touch app.py
> touch BTPServices.py
> touch ProcFile
> touch requirements.txt
> touch runtime.txt
> touch manifest.yml
The given command must be run in the SAP Business Application Studio terminal. Once the installation package is in place, you can then open app.py and introduce a get method to procure a list of suppliers from the SAP S/4HANA Cloud system. However, before we proceed, it's important to touch upon the Python packages used to realize this Python web-based application. There are numerous Python web frameworks at our disposal, many of which are open-source. The more popular ones include Django, CherryPy, Falcon, Flask, and Tornado. From this list, I have chosen to construct the REST API using Flask due to its lightweight, RESTful web framework that carries a minimal technical debt.
In this example, I created a REST API to retrieve the list of suppliers from the SAP S/4HANA Cloud system using the OData service, and put together a wrapper to return the response as a RESTful API response in JSON format. These APIs are asynchronous and are built using WSGI (Web Server Gateway Interface). Below is a code snippet screenshot of app.py for your perusal.
# importing modules
# ---------------------------------------------------------------------
# import all the necessary modules here that will be used in the program
from flask import Flask, jsonify
import os
import requests
from requests.auth import HTTPBasicAuth
# importing local module: BTPservices: containing generic codes for destination
# ---------------------------------------------------------------------
import BTPServices
# application initialization
# ---------------------------------------------------------------------
app = Flask(__name__)
# data fetch using the destination
# ---------------------------------------------------------------------
@app.route('/getSuppliers', methods=['GET'])
def getSuppliersES5():
lv_request = getSuppliersList('ES5', '/sap/opu/odata/sap/EPM_REF_APPS_SHOP_SRV/Suppliers?$format=json')
return jsonify(lv_request)
# fetching of records having BasicAuthentication authorization
# ---------------------------------------------------------------------
def getSuppliersList(lv_dest, lv_string):
lv_usr = ""
lv_pass=""
lv_destination = BTPServices.getDestination(sDestinationService='python_dest_service', sDestinationName=lv_dest)
if lv_destination is None:
return "Error: Destination not found"
lv_url = lv_destination['destinationConfiguration']['URL'] + lv_string
lv_usr = lv_destination['destinationConfiguration']['User']
lv_pass = lv_destination['destinationConfiguration']['Password']
try:
lv_request = requests.get(lv_url, headers={'Accept': 'application/json'}, auth=HTTPBasicAuth(lv_usr, lv_pass))
lv_request.raise_for_status()
except requests.exceptions.HTTPError as err:
return jsonify(replies=str(err))
response_json = lv_request.json()
# clearing variables
del lv_destination, lv_url, lv_usr, lv_pass
return response_json
Here you will notice that I utilized the Flask framework in Python and imported the necessary modules for the code. I then invoked the getSuppliersES5 method to retrieve a list of suppliers. This method, in turn, calls the getSuppliersList method, which calls a generic method to obtain information from an instance that has been created. It retrieves the details of the destination named "ES5.” Subsequently, it establishes a connection and acquires the suppliers' data from the ES5 demo system of the SAP S/4HANA Cloud system. After receiving the response, I could convert it into a JSON response.
Here's a code snippet of BTPServices.py for the SAP BTP destination connection setup.
from cfenv import AppEnv
import requests
def getDestination(sDestinationService, sDestinationName):
# Read the environment variables
# -------------------------------------------------------------------------------
env = AppEnv()
dest_service = env.get_service(name=sDestinationService)
if dest_service is None:
print(f"Service {sDestinationService} not found")
return None
sUaaCredentials = dest_service.credentials['clientid'] + ':' + dest_service.credentials['clientsecret']
# Request a JWT token to access the destination service
# -------------------------------------------------------------------------------
headers = {'Authorization': 'Basic '+sUaaCredentials, 'content-type': 'application/x-www-form-urlencoded'}
form = [('client_id', dest_service.credentials['clientid'] ),('client_secret', dest_service.credentials['clientsecret'] ), ('grant_type', 'client_credentials')]
url = dest_service.credentials['url'] +"/oauth/token"
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = requests.request("POST", url, headers=headers, data=form)
# Search your destination in the destination service
# -------------------------------------------------------------------------------
token = response.json()["access_token"]
headers= { 'Authorization': 'Bearer ' + token }
r = requests.get(dest_service.credentials['uri'] + '/destination-configuration/v1/destinations/'+sDestinationName, headers=headers)
print("DEST URI:",dest_service.credentials['uri'])
# Access the destination securely
# -------------------------------------------------------------------------------
destination = r.json()
return destination
The above code is to show how to establish the connection with the destination service and get the URL and other details of the ES5 system, using the JWT token mechanism.
Now create the remaining three files mentioned in the figure below, since they are required to run the application configurations.
The package version may change in the future based on the releases of these libraries.
Deployment Steps
Once the application changes are done, now we need to deploy the application in SAP BTP. The first step would be to create the manifest.yml to define the deployment configurations.
---
applications:
- name: myPythonApp
routes:
- route: app-python.cfapps.ap21.hana.ondemand.com
path: ./
memory: 128M
stack: cflinuxfs4
disk_quota: 512M
buildpack: python_buildpack
command: python3 app.py
services:
- python_dest_service
Follow these steps:
- Log in to SAP BTP applications: cf login -a “api end points”
- Cf login -a https://api.cf.ap21.hana.ondemand.com
- Enter the email ID and password.
- Execute the command to create the destination service instance “python_dest_service”
- cf create-service destination lite python_dest_service
- Execute the command cf push (make sure the manifest.yml file is in the current folder path) as shown below.
After the successful deployment of the application, navigate to the SAP BTP subaccounts, click on the dev space, and then click on the deployed app as mentioned in the manifest.yml file.
Now click on the URL as shown below (“Application url”). It will open the API endpoints in a new browser tab and append the text /getSuppliers.
Below is the response snapshot.
This is the process used to retrieve supplier data from an SAP S/4HANA Cloud system via a web application framework that utilizes the Python programming language.
Conclusion
This integration with SAP S/4HANA Cloud opens up new opportunities for other programming languages, such as Python, to fully exploit their capabilities in the implementation of such services, thereby enhancing the overall ecosystem. This post not only demonstrated the versatility of Python as a programming language, but also underscored its potential in enhancing the functionality and efficiency of SAP Business Application Studio.
Comments