This article is an excerpt from the broader set of changes to our documentation in preparation for Zato.

High-level overview

Zato and Python logo

Zato is a highly scalable, Python-based integration platform for APIs, SOA and microservices. It is used to connect distributed systems or data sources and to build API-first, backend applications. The platform is designed and built specifically with Python users in mind.

Zato is used for enterprise, business integrations, data science, IoT and other scenarios that require integrations of multiple systems.

Real-world, production Zato environments include:

  • A platform for processing payments from consumer devices

  • A system for a telecommunication operator integrating CRM, ERP, Billing and other systems as well as applications of the operator's external partners

  • A data science system for processing of information related to securities transactions (FIX)

  • A platform for public administration systems, helping achieve healthcare data interoperability through the integration of independent data sources, databases and health information exchanges (HIE)

  • A global IoT platform integrating medical devices

  • A platform to process events produced by early warning systems

  • Backend e-commerce systems managing multiple suppliers, marketplaces and process flows

  • B2B platforms to accept and process multi-channel orders in cooperation with backend ERP and CRM systems

  • Platforms integrating real-estate applications, collecting data from independent data sources to present unified APIs to internal and external applications

  • A system for the management of hardware resources of an enterprise cloud provider

  • Online auction sites

  • E-learning platforms

Zato offers connectors to all the popular technologies, such as REST, SOAP, AMQP, IBM MQ, SQL, Odoo, SAP, HL7, Redis, MongoDB, WebSockets, S3 and many more.

Running on premises, in the cloud, or under Docker, Kubernetes and other container technologies, Zato services are optimised for high performance - it is easily possible to run hundreds and thousands of services on typical server instances as offered by Amazon, Google Cloud, Azure or other cloud providers.

Zato servers offer high availability and no-downtime deployment. Servers form clusters that are used to scale systems both horizontally and vertically.

The software is 100% Open Source with commercial and community support available

A platform and language for interesting, reusable and atomic services

Zato promotes the design of, and helps you build, solutions composed of services which are interesting, reusable and atomic (IRA):

  • I for Interesting - each service should make its clients want to use it more and more. People should immediately see the value of using the service in their processes. An interesting service is one that strikes everyone as immediately useful in wider contexts, preferably with few or no conditions, prerequisites and obligations. An interesting service is aesthetically pleasing, both in terms of its technical usage as well as in its potential applicability in fields broader than originally envisaged. If people check the service and say "I know, we will definitely use it" or "Why don't we use it" you know that the service is interesting. If they say "Oh no, not this one again" or "No, thanks, but no" then it is the opposite.
  • R for Reusable - services can be used in different, independent business processes
  • A for Atomic - each service fullfils a single, atomic business need

Each service is deployed independently and, as a whole, they constitute an implementation of business processes taking place in your company or organisation.

With Zato, developers use Python to focus on the business logic exclusively and the platform takes care of scalability, availability, communication protocols, messaging, security or routing. This lets developers concentrate only on what is the very core of systems integrations - making sure their services are IRA.

Python is the perfect choice for API integrations, SOA and microservices, because it hits the sweet spot under several key headings:

  • It is a very high level language, with syntax close to how grammar of various spoken languages works, which makes it easy to translate business requirements into implementation
  • Yet, it is a solid, mainstream and full-featured, real programming language rather than a domain-specific one which means that it offers to developers a great degree of flexibility and choice in expressing their needs
  • Many Python developers have a strong web programming / open source background which means that it is little effort to take a step further, towards API integrations and backend servers. In turn, this means that it is easy to find good people for API projects.
  • Many Python developers have knowledge of multiple programming languages - this is very useful in the context of integration projects where one is typically faced with dozens of technologies, vendors or integration methods and techniques
  • Lower maintenance costs - thanks to the language's unique design, Python programmers tend to produce code that is easy to read and understand. From the perspective of multi-year maintenance, reading and analysing code, rather than writing it, is what most programmers do most of the time so it makes sense to use a language which makes it easy to carry out the most common tasks.

In short, Python can be construed as executable pseudo-code with many of its users already having roots in modern server-side programming so Zato, both from a technical and strategic perspective, is a natural choice for complex and sophisticated API solutions as a platform built in the language and designed for Python developers from day one.

More than services

Systems integrations commonly require two more features that Zato offers as well:

  • File transfer - allows you to move batch data between locations and to distribute it among systems and APIs

  • Single Sign-On (SSO) - a convenient REST interface lets you easily provide authentication and authorisation to users across multiple systems

Next steps

  • Start the tutorial to learn more technical details about Zato, including its architecture, installation and usage. After completing it, you will have a multi-protocol service representing a sample scenario often seen in banking systems with several applications cooperating to provide a single, consistent API to its callers.

  • Visit the support page if you would like to discuss anything about Zato with its creators

As we are preparing to release Zato 3.2 soon, all the programming examples are being rewritten to showcase what the platform is capable of. That includes REST examples too and this article presents a few samples taken from the documentation.

For fuller discussion and more examples - check the documentation.

Calling REST APIs

  • All data can be prepared as dict objects - this includes the payload, query string parameters, path parameters and HTTP headers too

  • Zato will fill in patterns in URL paths, e.g. if the path is /api/billing/{phone_no} then the code below will substitute 271637517 for phone_no and the rest of the parameters will go the query string

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

    # Zato
    from zato.server.service import Service

    class SetBillingInfo(Service):
        """ Updates billing information for customer.
        """
        def handle(self):

        # Python dict representing the payload we want to send across
        payload = {'billing':'395.7', 'currency':'EUR'}

        # Python dict with all the query parameters, including path and query string
        params = {'cust_id':'39175', 'phone_no':'271637517', 'priority':'normal'}

        # Headers the endpoint expects
        headers = {'X-App-Name': 'Zato', 'X-Environment':'Production'}

        # Obtains a connection object
        conn = self.out.rest['Billing'].conn

        # Invoke the resource providing all the information on input
        response = conn.post(self.cid, payload, params, headers=headers)

        # The response is auto-deserialised for us to a Python dict
        json_dict = response.data

        # Assign the returned dict to our response - Zato will serialise it to JSON
        # and our caller will get a JSON message from us.
        self.response.payload = json_dict

Accepting REST calls

  • Use self.request.payload to access input data - it is a dict object created by Zato out of the parsed JSON request
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class LogInputData(Service):
    """ Logs input data.
    """
    def handle(self):

        # Read input received
        user_id = self.request.payload['user_id']
        user_name = self.request.payload['user_name']

        # Store input in logs
        self.logger.info('uid:%s; username:%s', user_id, user_name)

Reacting to REST verbs

  • Implement handle_<VERB> to react to specific HTTP verbs when accepting requests

  • If the service is invoked with a verb that it does not implement, the API client receives status 405 Method Not Allowed

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

# Zato
from zato.server.service import Service

class MultiVerb(Service):
    """ Logs input data.
    """
    def handle_GET(self):
        self.logger.info('I was invoked via GET')

    def handle_POST(self):
        self.logger.info('I was invoked via POST')

Request and response objects

  • All data and metadata is available via self.request and self.response attributes. Security-related details are in self.channel.security.

Request object:

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

# Zato
from zato.server.service import Service

class RequestObject(Service):

    def handle(self):

        # Here is all input data parsed to a Python object
        self.request.payload

        # Here is input data before parsing, as a string
        self.request.raw_request

        # Correlation ID - a unique ID assigned to this request
        self.request.cid

        # A dictionary of GET parameters
        self.request.http.GET

        # A dictionary of POST parameters
        self.request.http.POST

        # REST method we are invoked with, e.g. GET, POST, PATCH etc.
        self.request.http.method

        # URL path the service was invoked through
        self.request.http.path

        # Query string and path parameters
        self.request.http.params

        # This is a method, not an attribute,
        # it will return form data in case we were invoked with one on input.
        form_data = self.request.http.get_form_data()

        # Username used to invoke the service, if any
        self.channel.security.username

        # A convenience method returning security-related details
        # pertaining to this request.
        sec_info = self.channel.security.to_dict()

Response object:

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

# Zato
from zato.server.service import Service

class ResponseObject(Service):

    # Returning responses as a dict will make Zato serialise it to JSON
    self.response.payload = {'user_id': '123', 'user_name': 'my.user'}

    # String data can also be always be returned too,
    # e.g. because you already have data serialised to JSON or to another data format
    self.response.payload = '{"my":"response"}'

    # Sets HTTP status code
    self.response.status_code = 200

    # Sets HTTP Content-Encoding header
    self.response.content_encoding = 'gzip'

    # Sets HTTP Content-Type - note that Zato itself
    # sets it for JSON, you do not need to do it.
    self.response.content_type = 'text/xml; charset=UTF-8'

    # A dictionary of arbitrary HTTP headers to return
    self.response.headers = {
        'Strict-Transport-Security': 'Strict-Transport-Security: max-age=16070400',
        'X-Powered-By': 'My-API-Server',
        'X-My-Header': 'My-Value',
    }

Next steps

This article is just a quick preview and if you are interested in building scalable and reusable API systems, you can start now by visiting the Zato main page, familiarising yourself with the extensive documentation or by going straight to the first part of the tutorial.

Be sure to visit our Twitter, GitHub and Gitter communities too!

With the imminent release of Zato 3.2, we are happy today to announce the availability of a new API integrations tutorial. Let's quickly check what it offers.

The tutorial is completely new and by following it, you will learn all of the following:

  • What is Zato and how it can be used as an API integrations platform and backend application server

  • How to think in terms of reusable API services

  • Zato installation under several platforms, including Linux distributions, Docker and Vagrant

  • Using PyCharm, Visual Studio Code and other IDEs with Zato

  • Developing Zato services and using its Dashboard for configuration

  • How to integrate with external systems, using REST and AMQP as example technologies

  • How to automate deployments

  • How to conduct automated API tests in plain English, without any programming

In short, after you complete it, you will acquire the core of what is needed to use Python to integrate complex API and backend systems.

Zato tutorial

# -*- coding: utf-8 -*-
# zato: ide-deploy=True

# Zato
from zato.server.service import Service

class GetUserDetails(Service):
    """ Returns details of a user by the person's ID.
    """
    name = 'api.user.get-details'

    def handle(self):

        # For later use
        user_name = self.request.payload['user_name']

        # Get data from CRM ..
        crm_data = self.invoke_crm(user_name)

        # .. extract the CRM information we are interested in ..
        user_type = crm_data['UserType']
        account_no = crm_data['AccountNumber']

        # .. get data from Payments ..
        payments_data = self.invoke_payments(user_name, account_no)

        # .. extract the CRM data we are interested in ..
        account_balance = payments_data['ACC_BALANCE']

        # .. optionally, notify the fraud detection system ..
        if self.should_notify_fraud_detection(user_type):
            self.notify_fraud_detection(user_name, account_no)

        # .. now, produce the response for our caller.
        self.response.payload = {
          'user_name': user_name,
          'user_type': user_type,
          'account_no': account_no,
          'account_balance': account_balance,
      }

Zato tutorial

Zato tutorial

Click here to get started - and remember to visit our Twitter, GitHub and Gitter communities as well.

In this article, we are going to use Zato in its capacity as a multi-protocol Python API gateway - we will integrate a few popular technologies, accepting requests sent over protocols commonly used in frontend systems, enriching and passing them to backend systems and returning responses to the API clients using their preferred data formats. But first, let's define what an API gateway is.

Clearing up the terminology

Although we will be focusing on complex API integrations later on today, to understand the term API gateway we first need to give proper consideration to the very term gateway.

What comes to mind when we hear the word "gateway", and what is correct etymologically indeed, is an opening in an otherwise impermissible barrier. We use a gateway to access that which is in other circumstances inaccessible for various reasons. We use it to leave such a place toox.

In fact, both "gate" and the verb "to go" stem from the same basic root and that, again, brings to mind a notion of passing through space specifically set aside for the purpose of granting access to what normally would be unavailable. And once more, when we depart from such an area, we use a gateway too.

From the perspective of its true intended purpose, a gateway letting everyone in and out as they are would amount to little more than a hole in a wall. In other words, a gateway without a gate is not the whole story.

Yes, there is undoubtedly an immense aesthetic gratification to be drawn from being close to marvels of architecture that virtually all medieval or Renaissance gates and gateways represent, but we know that, contemporarily, they do not function to the fullest of their capacities as originally intended.

Rather, we can intuitively say that a gateway is in service as a means of entry and departure if it lets its operators achieve the following, though not necessarily all at the same time, depending on one's particular needs:

  • Telling arrivals where they are, including projection of might and self-confidence
  • Confirming that arrivals are who they say they are
  • Checking if their port of origin is friendly or not
  • Checking if they are allowed to enter that which is protected
  • Directing them to specific areas behind the gateway
  • Keeping a long term and short term log of arrivals
  • Answering potential questions right by the gate, if answers are known to gatekeepers
  • Cooperating with translators and coordinators that let arrivals make use of what is required during their stay

We can now recognise that a gateway operates on the border of what is internal and external and in itself, it is a relatively narrow, though possibly deep, piece of an architecture. It is narrow because it is only through the gateway that entry is possible but it may be deeper or not, depending on how much it should offer to arrivals.

We also keep in mind that there may very well be more than a single gateway in existence at a time, each potentially dedicated to different purposes, some overlapping, some not.

Finally, it is crucial to remember that gateways are structural, architectural elements - what a gateway should do and how it should do it is a decision left to architects.

With all of that in mind, it is easy to transfer our understanding of what a physical gateway is into what an API one should be.

  • API clients should be presented with clear information that they are entering a restricted area
  • Source IP addresses or their equivalents should be checked and requests rejected if an IP address or equivalent information is not among the allowed ones
  • Usernames, passwords, API keys and similar representations of what they are should be checked by the gateway
  • Permissions to access backend systems should be checked seeing as not every API client should have access to everything
  • Requests should be dispatched to relevant backend systems
  • Requests and responses should be logged in various formats, some meant to be read by programs and applications, some by human operators
  • If applicable, responses can be served from the gateway's cache, taking the burden off the shoulders of the backend systems
  • Requests and responses can be transformed or enriched which potentially means contacting multiple backend systems before an API caller receives a response

We can now define an API gateway as an element of a systems architecture that is certainly related to security, permissions and granting or rejecting access to backend systems, applications and data sources. On top of it, it may provide audit, data transformation and caching services. The definition will be always fluid to a degree, depending on an architect's vision, but this is what can be expected from it nevertheless.

Having defined what an API gateway is, let's create one in Zato and Python.

Clients and backend systems

In this article, we will integrate two frontend systems and one backend application. Frontend ones will use REST and WebSockets whereas the backend one will use AMQP. Zato will act as an API gateway between them all.

Zato as a Python API gateway architecture

Not granting frontend API clients direct access to backend systems is usually a good idea because the dynamics involved in creation of systems on either side are typically very different. But they still need to communicate and hence the usage of Zato as an API gateway.

Python code

First, let's show the Python code that is needed to integrate the systems in our architecture:

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

# Zato
from zato.server.service import Service

class APIGateway(Service):
    """ Dispatches requests to backend systems, enriching them along the way.
    """
    name = 'api.gateway'

    def handle(self):

        # Enrich incoming request with metadata ..
        self.request.payload['_receiver'] = self.name
        self.request.payload['_correlation_id'] = self.cid
        self.request.payload['_date_received'] = self.time.utcnow()

        # .. AMQP configuration ..
        outconn = 'My Backend'
        exchange = '/incoming'
        routing_key = 'api'

        # .. publish the message to an AMQP broker ..
        self.out.amqp.send(data, outconn, exchange, routing_key)

        # .. and return a response to our API client.
        self.response.payload = {'result': 'OK, data accepted'}

There are a couple of points of interest:

  • The gateway service enriches incoming requests with metadata but it could very well enrich it with business data too, e.g. it could communicate with yet another system to obtain required information and only then pass the request to the final backend system(s)

  • In its current form we send all the information to AMQP brokers only but we could just as well send it to other systems, possibly modifying the requests along the way

  • The code is very abstract and all of its current configuration could be moved to a config file, Redis or another data source to make it even more high-level

  • Security configuration and other details are not declared directly in the body of the gateway service but they need to exist somewhere - we will describe it in the next section

Configuration

In Zato, API clients access the platform's services using channels - let's create a channel for REST and WebSockets then.

First REST:

Zato Dashboard REST menu

Zato Dashboard REST channel creation form

Now WebSockets:

Zato Dashboard REST channel creation form

We create a new outgoing AMQP connection in the same way:

Zato Dashboard outgoing AMQP connection form

Using the API gateway

At this point, the gateway is ready - you can invoke it from REST or WebSockets and any JSON data it receives will be processed by the gateway service, the AMQP broker will receive it, and API clients will have replies from the gateway as JSON responses.

Let's use curl to invoke the REST channel with JSON payload on input:

  $ curl http://api:<password-here>@localhost:11223/api/v1/user ; echo
  curl --data-binary @request.json http://localhost:11223/api/v1/user ; echo
  {"result": "OK, data accepted"}
  $

Taken together, the channels and the service allowed us to achieve this:

  • Multiple API clients can access the backend AMQP systems, each client using its own preferred technology
  • Client credentials are checked on input, before the service starts to process requests (authentication)
  • It is possible to assign RBAC roles to clients, in this way ensuring they have access only to selected parts of the backend API (authorisation)
  • Message logs keep track of data incoming and outgoing
  • Responses from channels can be cached which lessens the burden put on the shoulders of backend systems
  • Services accepting requests are free to modify, enrich and transform the data in any way required by business logic. E.g., in the code above we only add metadata but we could as well reach out to other applications before requests are sent to the intended recipients.

We can take it further. For instance, the gateway service is currently completely oblivious to the actual content of the requests.

But, since we just have a regular Python dict in self.request.payload, we can with no effort modify the service to dispatch requests to different backend systems, depending on what the request contains or possibly what other backend systems decide the destination should be.

Such additional logic is specific to each environment or project which is why it is not shown here, and this is also why we end the article at this point, but the central part of it all is already done, the rest is only a matter of customisation and plugging in more channels for API clients or outgoing connections for backend systems.

Finally, it is perfectly fine to split access to systems among multiple gateways - each may handle requests from selected technologies on the one hand but on the other hand, each may use different caching or rate-limiting policies. If there is more than one, it may be easier to configure such details on a per-gateway basis.

Learn more

If you are interested in building scalable and reusable API systems, you can start now by visiting the Zato main page, familiarising yourself with the extensive documentation or by going straight to the first part of the tutorial.

Be sure to visit our Twitter, GitHub and Gitter communities too!

We begin in 2021 with a deep dive into Zato REST API channels. What are they? How to use them efficiently? How can they configured for maximum flexibility? Read on to learn all the details.

A sample service

First, let's have a look at a sample service that we want to make available to API clients.

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

# Zato
from zato.server.service import Service

class GetUserDetails(Service):
    """ Returns details of a selected user.
    """
    name = 'api.user.get-details'

    class SimpleIO:
        input_required = 'user_name'
        output_required = 'email', 'user_type'

    def handle(self):

        # Log what we are about to do.
        self.logger.info('Returning details of `%s`', self.request.input.user_name)

        # In real code, we would look up the details in a database,
        # but not necessarily in a cache - read the article why it is not needed.
        details = {
            'email': 'my.user@example.com',
            'user_type': 'ABC'
        }

        # Return the response now.
        self.response.payload = details

The first thing that may strike you is that the code is on a very high level - it just has access to a user_name and some data is returned but there is no mention of REST, no data serialisation, caching or anything that is not the business functionality of returning user details.

This is by design. In Zato, services focus on what they actually need to do and the lower-level details are left to the platform. In other words, the service does not need to be concerned with peculiarities of a given transport method, it just has its input to process and output to produce. It is channels in front of a service that deal with all such aspects and the service concentrates on higher level logic.

This makes it possible to employ the same service in other contexts - for instance, we are describing REST channels today but the very same service could be invoked from the scheduler, through AMQP, IBM MQ or via other channels, including multiple REST ones, helping you in this way design a reusable Service-Oriented Architecture (SOA).

With that in mind, we can advance to REST channels now.

REST API channels

In Zato web-admin, a definition of a sample REST channel making use of our service may look like below.

Zato web-admin channels menu

Creating a REST channel in Zato web-admin

Now that we have created a new channel, we can invoke it to confirm that it works as expected.

% curl localhost:17010/api/v1/user/my.username ; echo
{"email": "my.user@example.com", "user_type": "ABC"}
%

In server logs:

INFO - api.user.get-details - Returning details of `my.username`

Everything is fine and we can proceed.

Just one note about channels, remember that there can be many channels pointing to the same service - this lets you reuse the services in various scenarios, e.g. you can have a separate REST channel with its own security definition for each external application connecting to your APIs.

Whenever you add, modify or delete a channel, the service as such is unchanged, nor are any other channels. Conversely, when you update a service, for instance adding new functionality, all channels using it will automatically invoke the new version of the service.

Channels come with good defaults when you create them but it is always possible to customise them to one's particular needs. Let's go step by step through each attribute of a channel's definition.

Basic information

  • Name - Each channel has a unique name which can be arbitrary, depending on your naming conventions.

  • Active - An inactive channel cannot be invoked; doing so will yield a 404 error.

URL path & query string

  • URL path - URL paths need to be unique. Each can contain one or more patterns to match input parameters - this is why in our service we were able to reference self.request.input.user_name - it was extracted from the URL path.

  • Match slash - Sometimes, URL path parameters sent from API clients will contain the slash character which normally is used to separate path components. This checkbox controls whether path patterns should match a slash or not.

  • URL params - QS over path vs. Path over QS. Usually, applications will send parameters in one place only, e.g. only in the URL path or in query string parameters. But what if an application has good reasons to send parameters in both the query string and URL path, for instance /api/v1/user/my.username?user_name=my.other.username - this happens from time to time and this setting lets one control which of the two will take precedence.

  • Merge to request - Used if parameters are sent via query string in addition to the URL path. If checked, such query string parameters will be accessible through self.request.input, otherwise, they will exist only in self.request.http.GET.

  • Params priority - This is similar to the options above but it will control the behaviour if parameters are sent in both JSON message body as well as in URL path or query string - it lets one decide which will have higher priority and which will become available in self.request.input.

HTTP metadata & data format

  • Method - it is possible to specify that only specific HTTP method can be used to invoke the channel. This is not always needed. For instance, the service above can work just fine with either GET or POST, depending on what the caller prefers. Conceptually, this is a GET request but some API clients will always use POST so this is why filling out this field is not always needed or advised.

A service can handle multiple methods either as a whole and a channel can dispatch requests to specific parts of the service depending on which method is used, i.e. you can add handle_GET, handle_POST and other such methods independently, resulting, for instance, in a User service that handles CRUD via respective handle_* methods.

  • Encoding - Can be set to "gzip" to enable compression of responses from the channel.

  • Data format - Can be one of JSON, XML or HL7 to enable auto-de/serialisation of requests and responses. Note that the original request, prior to any processing, is always available in self.request.raw_request.

  • Accept header - To what Accept HTTP headers the channel should react. Note that, just like with methods, it is possible for the service to handle each header separately, which lets one have the same service produce different responses depending on what the client's Accept header dictates.

API service & security

  • Service - The service that is mounted on this channel and which will be given incoming requests on input, as in the code example above. The same service may be mounted on multiple channels.

  • Security definition - What kind of an authentication mechanism this channel requires. Can be one of Basic Auth, API key, JWT, Vault, WS-Security or XPath. Each channel may have a different security definition assigned and the same definition can be assigned to multiple channels. Note that, to avoid any misunderstandings, you need to explicitly choose "No security definition" if the channel should not handle authentication itself, perhaps becaues the service should do it on its own, i.e. it is not possible to forget to choose something here and leave a channel unsecured by mistake.

  • RBAC - A channel can also use Role-Based Access Control definitions where each API client is assigned fine-grained permissions to individual methods and roles, possibly hierarchical one, which control if a particular client can invoke the channel's service. For instance, some API clients may be allowed to only read (GET) data whereas different ones will be able to create, update and delete it too (POST, PATCH and DELETE).

Cache

  • Cache type - Optionally, can be set to either built-in or Memcached. Requests matching previous ones will be automatically served from a specific cache assigned to the channel. With the built-in cache, the response is served from RAM directly, resulting in very fast responses. It is possible to browse, modify or delete the cached data, as below:

Zato web-admin built-in cache list

Zato web-admin built-in cache entry details

Rate limiting

The rate limiting stanza was not expanded previously so let's do it now to add a rate limiting definition to our channel. As usual, the limits can be set separately for each channel.

Zato web-admin channel's rate limiting definition

In this particular case, clients connecting from the internal network will be allowed to issue 30 request per minute but connections from localhost can invoke it 50k times an hour. And everyone else is limited to 100 requests a day.

Message log

Just like with rate limiting, these options were not expanded in the initial screenshot so here they are. Each channel can keep N last messages received, sent or both. It is also possible to say that only the first X kilobytes of a given message are to be stored - some messages may be too large for it to be practical to keep them in their entirety. When the log becomes full, the oldest messages are discarded, making room for newer ones.

Zato web-admin channel's message log definition

Stored messages can be browsed in web-admin, immediately letting one know what a given channel receives and sends.

Zato web-admin channel's message log definition

Such a message log is a feature common to other elements of Zato, e.g. HL7 or WebSocket connections have their own message logs too.

Documentation and OpenAPI (WSDL too)

It is good that we have a REST channel but how do we let others know about it? On the one hand, you can simply notify your partners and clients through documentation, wiki pages or other non-automated means.

On the other hand, you can also supply auto-generated API documentation and OpenAPI definitions, like below. This means that API clients matching your services can be generated automatically.

Auto-generated API documentation index file

Auto-generated API documentation service file

And by the way, if you need a WSDL for SOAP clients, the generated documentation includes it too.

Invoking REST APIs

This is everything about REST channels today but one question may be still open. If channels are means for handling incoming connections then how does one make requests to REST API endpoints external to Zato? How to invoke other other people's microservices?

The answer is that this is what Zato outgoing connections are for and we will cover REST outgoing connections in a future post in a way similar to how we went through REST channels in this one.

Learn more

If you are interested in building scalable and reusable API systems, you can start now by visiting the Zato main page, familiarising yourself with the extensive documentation or by going straight to the first part of the tutorial.

Be sure to visit our Twitter, GitHub and Gitter communities too!