Creating dashboards for backend systems

While Zato is primarily meant to be used as middleware and backend application server, it is also capable of producing frontend dashboards that API systems often require.

Typical examples include:

  • Online process monitoring dashboards
  • Dashboards for batch processing-based integrations
  • Outputting HTML for already existing dashboards that cannot invoke REST or process JSON

To support these use cases, Zato services can produce HTML, CSS, JavaScript or similar responses. Such output can be produced using Jinja (Django) templates as well.

Services that produce frontend content have a name of frontend services, unlike API services that return JSON or other machine-readable data formats.

How it works

The process of authoring frontend services has several key steps:

  • Create a channel or channels for your services
  • Author the services
  • Deploy the services in a secure manner

Creating frontend channels

Similar to the API services, the communication between a frontend and frontend services happens through one or more REST channels.

For instance, here is a sample channel pointing to a service that returns a CSS document.

There are two points of interest in the screenshot above:

  • Data format is not set to any specific one. This is because we are going to use the Content-Type HTTP header in the service in a moment explicitly.

  • The URL path is arbitrary and in no way does it have to map 1:1 to actual files from the server's disk.

  • The channel is configured to cache its responses for 60 minutes. It means that once the CSS is returned, any subsequent invocation of this endpoint will serve its response directly from RAM of the operating system that a given Zato server runs. Caching of responses is not strictly necessary but it does make sense to apply it with static resources that seldom change.

The above will work very well but there is one aspect to observe - the URL path points to a single static resource only. It means that, if we need to return multiple files, such as more than one CSS style sheet, we will need to create a separate channel for each such resource.

Instead of that, we can create a reusable channel that will work with multiple paths, using path parameters, as below. In this way, the caller (e.g. a browser or another frontend application) will be able to request arbitrary files but only one REST channel will have to be created.

Notice that the name of the path is now provided through a {path} parameter. When this channel is invoked, its underlying service, api.frontend.static, will receive this path on input. Once more, the value of the path can be arbitrary and it does not have to represent a real file on disk. Note also that caching is not enabled below - it is an optional feature that does not have to be enabled unless required.

The rest of the chapter will assume that the "API Frontend Static" exists and the focus will be on the inner workings of the "api.frontend.static" service.

Authoring frontend services

A frontend service is one that returns content suitable for frontend purposes. That is, there are no inherent differences between creating frontend and API services in Zato. It is merely a question of returning HTML, CSS or similar types of information instead of JSON, FHIR and other more backend-oriented formats.

Here is service "api.frontend.static" available through the REST "API Frontend Static" channel defined in the previous section.

Note that, in this particular case, all the frontend resources are embedded directly in the same Python module that the service is in but, in more complex scenarios, they could be stored in files on disk or at remote addresses access on demand by the service.

In this way, any kind of frontend resources needed for custom dashboards can be returned directly from Zato services.

# -*- coding: utf-8 -*-

# stdlib
from http.client import NOT_FOUND
from mimetypes import guess_type

# Zato
from zato.server.service import Service

# ########################################################################################
# ########################################################################################

style_css = """
* {
    color: navy;
}
"""

common_js = """
function hello() {
    console.log("Hello from Zato")
}
"""

# ########################################################################################
# ########################################################################################

config = {
    'style.css': style_css,
    'common.js': common_js,
}

# ########################################################################################
# ########################################################################################

class FrontedStatic(Service):

    # Name of this service
    name = 'api.frontend.static'

    # What the service requires on input
    input = 'path'

    def handle(self) -> 'None':

        # Holds information what was requested by the frontend
        path = self.request.input.path

        # Try to look up this path in our configuration
        value = config.get(path)

        # If there is no value, it means that the path is not found in the configuration,
        # which means that we can return an error. In this case, it will be 404 Not Found.
        if not value:
            self.response.status_code = NOT_FOUND
            self.response.content_type = 'text/plain'

        # Otherwise, we can produce the expected response now.
        else:

          # Auto-find the correct MIME type for the value being returned ..
          mime_type = guess_type(path)
          mime_type = mime_type[0]

          # .. populate the payload that we are returning ..
          self.response.payload = value

          # .. and set the MIME type as well.
          self.response.content_type = mime_type

# ########################################################################################
# ########################################################################################

Now, when a browser accesses a path that the service recognizes:

Here is what happens when the path is not recognized:

Security considerations

Serving static resources is inherently connected with accepting arbitrary user input from frontend applications. If files are served from disk, and input data maps 1:1 to real file names, care must be taken to ensure that the paths requested by frontend are not outside the boundaries of a directory or directories that the static resources should be served from.

For instance, an attacker may attempt to send requests with URL paths such as /static/../../../.ssh/id_rsa to try to extract data from system files containing sensitive information.

It is imperative that input be sanitized and validated before real files are served from disk.

Learn more


Schedule a meaningful demo

Book a demo with an expert who will help you build meaningful systems that match your ambitions

"For me, Zato Source is the only technology partner to help with operational improvements."

— John Adams
Program Manager of Channel Enablement at Keysight