Skip to Content
Technical Articles

Serving Fiori Applications with Python Flask, part 2

Welcome back to Serving Fiori Applications with Python Flask. In part 1, we looked at how you can make a basic Fiori template app with launchpad, tile, and a master/detail floor plan. We saw how easy it is to set up the Python framework with out-of-the-box Flask. The application however is not production grade as highlighted by the Flask authors. However, there is a large array of options to achieve this through Apache Gunicorn, pre-built cloud services, or a popular technology used with SAP Data Hub, Docker.

So, in this part we will take the same code base and update it with some Docker components including a versatile open source database, OrientDB. We won’t connect the application to OrientDB in this part of the series but we will show how to include it in the setup for future use in the application being built. Given that, let’s jump in.

Why would you be interested in this series?

  • You want to follow up from part 1 and see what else Flask can do to scale application development.
  • You really like SAP Data Hub and want to see what else Docker can do
  • You want to see the value in a multi-modal database like OrientDB

What should you have to complete this series?

  • Basic Python knowledge
  • Basic Docker with it installed on your testing system
  • Access to Github for sample code

Starting with the folder structure we can see changes from the original project with new docker related files. Each of these are used to spin up a stand-alone container with the application and required resources such as a java environment, databases and port assignment.

The Dockerfile is where we set up the base environment and OS which can be selected from a wide variety of options including official and approved images. Python 3.7 is a standard official image but we need to add some additional Java installations to run OrientDB. Once complete, the Dockerfile continues with other commands such as installing the Python dependencies and running the app that would otherwise be manually entered. So, this automates the tedious processes you might have done before in spinning up an app. This is a one-click operation.

#Dockerfile
FROM python:3.7
MAINTAINER Lynn Scheinman <lynn.scheinman@sap.com>

RUN apt-get update && apt-get install -qq -y \
  build-essential libpq-dev --no-install-recommends

RUN apt-get install default-jre -y
RUN apt-get install default-jdk -y

ENV INSTALL_PATH /fioriapp
RUN mkdir -p $INSTALL_PATH

WORKDIR $INSTALL_PATH

COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

COPY . .

CMD gunicorn -b 0.0.0.0:8000 --access-logfile - "fioriapp.app:create_app()"

The docker-compose.yml is the next level of automation to ensure all the components such as the app code, supporting databases and their ports are established and exposed for integration. In this case we are going to have 3 supporting components for the application. All open source and proven in production environments. The first is Postgres which will handle session data, then Orientdb for operational data, and lastly celery for running asynchronous tasks.

# docker-compose.yml
version: '2'

services:
  website:
    build: .
    command: >
      gunicorn -b 0.0.0.0:8000
        --access-logfile -
        --reload
        "fioriapp.app:create_app()"
    environment:
      PYTHONUNBUFFERED: 'true'
    volumes:
      - '.:/fioriapp'
    ports:
      - '8000:8000'

  postgres:
    image: 'postgres:9.5'
    env_file:
      - '.env'
    volumes:
      - 'postgres:/var/lib/postgresql/data'
    ports:
      - '5432:5432'

  orientdb:
    image: 'orientdb:2.2.20'
    command: 'dserver.sh'
    ports:
      - '2424:2424'
      - '2480:2480'
    environment:
      ORIENTDB_ROOT_PASSWORD: 'root'
    volumes:
      - '/var/orientdb/databases:/opt/orientdb/databases'

  celery:
    build: .
    command: celery worker -l info -A fioriapp.blueprints.contact.tasks
    env_file:
      - '.env'
    volumes:
      - '.:/fioriapp'


volumes:
  postgres:
  orientdb:

To initialize the application, you must have Docker installed. After a simple git clone command, you can then run the application with from the parent directory where the docker-compose.yml is contained. Using Docker-compose is recommended to manage container deployment. First, running docker-compose build will download the python3.7 image from the dockerfile. Then running, docker-compose up will start up all the components listing out the progress of each in the messages you may have seen from command line before.

In this case you can see a sample of the OrientDB output as Docker-compose sets up the application. Looking closely at the first 2 lines we can see it is listening on the ports assigned in the docker-compose.yml. If you go to your web browser and go to your localhost at port 2480, you should be introduced to the nice OrientDB welcome screen and then can setup a database in the container.

In addition, you should see a message that the app is listening at port 8000. So likewise, we can go see the app we set up in the first part of the series but now on a production ready Apache Gunicorn server. The Flask app itself is still listening on port 5000 but Gunicorn is managing all communication with it and therefore listens on HTTP traffic at 8000 to serve requests.

That covers the production environment setup. One-click and you have the same SAP Fiori app established in a self contained environment but with connections that enable scalable deployment. But we didn’t see how Flask has additional out of the box functionality to help us at the middleware level and making our app more friendly for Dev Ops or scaling in other means.

The main component we have here is called Blueprints. This is something already familiar to the way a Fiori application is set up with pages being registered in a main component controller. Each Flask Blueprint represents another functionality or set of utilities that are extensions of the existing infrastructure. They are independent but based on the common environment variables that were set up in Docker.

# \fioriapp\app.py

def create_app():   
    app = Flask(__name__)
    app.register_blueprint(home)
    app.register_blueprint(dashboard)

To initialize a blueprint within this refactored structure we need the well known __init__..py method and within it include the views which contains the routing logic.

# fioriapp\blueprints\dashboard\__init__.py
from fioriapp.blueprints.dashboard.views import dashboard

Then in the routes we define the blueprint as an app based on its functionality on line 6. The remainder of the code is the same as part 1 but instead we are calling our app a dashboard and thus the change in decorator.

# fioriapp\blueprints\dashboard\views.py
from flask import jsonify, Blueprint
from datetime import datetime
import time


dashboard = Blueprint('dashboards', __name__)


@dashboard.route('/DashboardAnalytics', methods=["GET"])
def DashboardAnalytics():
    """
    Return a simple odata container with date time information
    :return:
    """
    odata = {
        'd': {
            'results': []
        }
    }
    i = 0
    names = 'abcdefghijklmnopqrxtu'
    while i < 20:
        odata['d']['results'].append({
            "id": i,
            "name": names[i],
            "datetime": datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S'),

        })
        i+=1

    return jsonify(odata)

Using the Blueprint factorization concept, we can see that we’ve separated the functionality of the original application into a home and dashboard. The home represents the launchpad routes and back end functionality while the dashboard represents a separate app with its own set of routes in the views.py file.

In this case we are still maintaining all the Fiori UX code in the static and templates folders as in the previous part. As Flask is not opinionated, it leaves the option to additionally factor this code into application specific folders. This option can be implemented with augmenting the code above to the example below and then moving the Fiori files to their appropriate folders. But for the example in this step we leave the UX code base in place where a single team of UX developers can focus and separate back end developers can work in each of their application specific routing functions.

That wraps up this part of the series where we extended Flask into a Dockerized application with supporting databases. In the next part we’ll dive deeper into OrientDB and develop out the application using the very nice Fiori Network Graph library.

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