Skip to Content
Technical Articles
Author's profile photo Kallol Chakraborty

Easy way to access OData services via btp destinations in a python flask app


In this new world of BTP, I was wondering whether I can run python applications in the cloud foundry & perform several things like the followings:

  1. accessing the data of different systems(S4H On-Premise, ECC, BTP CAP OData services, etc.) via destinations.
  2. running python flask applications having multiple functionalities/pages.

I have checked a few places & found bits and pieces of information. I have tried & failed a few times to achieve the same. At last, I succeeded. So, I am consolidating everything in this blog post. Feel free to add information if I miss something. 

What is a python flask application? Ref.

There are many modules or frameworks which allow building your webpage using python like bottle, Django, Flask, etc. But the really popular ones are Flask and Django. Django is easy to use as compared to Flask but Flask provides you with the versatility to program with.

To understand what Flask is you have to understand a few general terms.

  1. WSGI: Web Server Gateway Interface (WSGI) has been adopted as a standard for Python web application development. WSGI is a specification for a universal interface between the web server and the web applications.
  2. Werkzeug: It is a WSGI toolkit, which implements requests, response objects, and other utility functions. This enables building a web framework on top of it. The Flask framework uses Werkzeug as one of its bases.
  3. jinja2: jinja2 is a popular templating engine for Python. A web templating system combines a template with a certain data source to render dynamic web pages.

Flask is a web application framework written in Python. Flask is based on the Werkzeug WSGI toolkit and Jinja2 template engine. Both are Pocco projects.

If you want to create your first local python flask application then follow this link.



There is a need for 6 files each having special functions. They are the following.

    1. It is the main python application file containing all the necessary codes.
      # importing modules
      # ---------------------------------------------------------------------
      # import all the necessary modules here that will be used in the program
      from flask import Flask, request, jsonify
      import os
      # importing local module: BTPservices: containing generic codes
      # ---------------------------------------------------------------------
      import BTPservices
      # application initialization
      # ---------------------------------------------------------------------
      app = Flask(__name__)
      # fetching port details
      # ---------------------------------------------------------------------
      cf_port = os.getenv("PORT")
      # fetching of records having OAuth2ClientCredentials authorization
      # ---------------------------------------------------------------------
      def get_records_01(lv_dest, lv_string):
          lv_destination = BTPservices.getDestination(sDestinationService=service_name_001, sDestinationName=lv_dest)
          lv_url = lv_destination['destinationConfiguration']['URL'] + lv_string
              lv_request = requests.get(lv_url, headers={'Accept': 'application/json'})
          except requests.exceptions.HTTPError as err:
              return jsonify(replies=err)    
          lv_request = lv_request.json()
      # clearing variables
          del lv_destination, lv_url    
          return lv_request.json()
      # fetching of records having OAuth2Password/No authorizartion
      # ---------------------------------------------------------------------
      def get_records_02(lv_dest, lv_string, lv_flag):
          lv_destination = BTPservices.getDestination(sDestinationService=service_name_001, sDestinationName=lv_dest)
      # having authorization    
          if lv_flag == 'True':
              lv_token = str(lv_destination['authTokens'][0]['http_header']['value'])
              lv_headers = {'Authorization': lv_token}
              lv_response = requests.get(lv_destination['destinationConfiguration']['URL'] + lv_string, headers=lv_headers)
      # having no authorization    
              lv_response = requests.get(lv_destination['destinationConfiguration']['URL'] + lv_string ) 
      # clearing the value    
          del lv_destination, lv_flag, lv_token
      # returns the data    
          return lv_response.json()
      # data fetch using the destination
      # ---------------------------------------------------------------------
      @app.route('/fetch_data_01', methods=['GET'])
      def fetch_data_01():
          lv_request = get_records_01('destination_name', 'entity_name')
          return lv_request
      @app.route('/fetch_data_02', methods=['GET'])
      def fetch_data_02():
          lv_request = get_records_02('destination_name', 'entity_name', 'True')
          return lv_request 
      # homepage
      # ---------------------------------------------------------------------
      @app.route('/', methods=['GET'])
      def home():
          lv_return = {
              "result": [
                      'message':  'Welcome to the homepage!',
                      'author':  'Kallol Chakraborty',
                      'date': '11/10/2022 ',
                      'description': 'The is a demo application'
          return jsonify(status='200', replies=lv_return)
      # main
      # ---------------------------------------------------------------------
      if __name__ == '__main__':
      # If the app is running locally
          if cf_port is None:
      # Use port 5000
    '', port=5000, debug=True)
      # Else use cloud foundry default port
    '', port=int(cf_port), debug=False)
    2. manifest.yml: The manifest.yml file represents the configuration describing your application and how it will be deployed to Cloud Foundry.IMPORTANT: Make sure you don’t have another application with the name app_name in your space. If you do, use a different name and adjust the whole tutorial according to it. Also bear in mind that your application’s technical name (in the route) must be unique in the whole Cloud Foundry landscape. The advice is that you use, for example, your subdomain name or part of your subaccount ID to construct the technical name. In this tutorial, we use: application-1234-abcd-007. The path to access the application will be
      - name: app_name
          - route:
        path: ./
        memory: 128M
        disk_quota: 512M
        buildpack: python_buildpack
        command: python
          - service_name_001

      service_name_001 is bound to the application now but it is not created yet. Please create the service: service_name_001 using the CF CLI command provided below.

      cf create-service destination lite service_name_001 
    3. ProcFile: The Procfile specifies the command line to execute the application at runtime.
      web: python
    4. runtime.txt: Specify the Python runtime version that your application will run on.
    5. requirements.txt: This application will be a web server utilizing the Flask web framework. To specify flask, requests, cfenv, etc. as an application dependencies, please check the below sample code.

      You can provide the versions also if you like.

    6. BTP is a very important file containing some generic codes & is responsible for fetching the details of the BTP destinations.
      # modules
      # -----------------------------------------------------------------------------------------------------
      from cfenv import AppEnv
      import requests
      def getDestination(sDestinationService, sDestinationName):
      # Read the environment variables  
      # -----------------------------------------------------------------------------------------------------
        env = AppEnv()
        dest_service = env.get_service(name=sDestinationService)
        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

Now, you need to create the destinations in the BTP account & try to access them via the python flask application.

That’s it. Happy coding 🙂


Ref. Using the Destination service in SAP BTP, Cloud Foundry Environment. Please check out this blogpost for more information.


Assigned Tags

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