Enterprise gRPC Services with Python and Zato

Overview

gRPC is a high-performance framework for building distributed systems and microservices. It leverages Protocol Buffers for serialization and HTTP/2 for transport, making it ideal for production environments requiring low-latency communication.

This Python integration with Zato demonstrates how to build scalable gRPC services with strongly-typed schemas. The approach enables efficient API orchestration and reliable data exchange between services using type-safe contracts.

Below you'll find a Protocol Buffer schema definition and an enterprise-ready API integration service showing end-to-end implementation.

Protocol Buffer Schema Definition

First, define your gRPC service contract using Protocol Buffers. This example shows a mandate registration service - a financial services process where a customer authorizes a merchant or service provider to automatically collect recurring payments from their bank account.

syntax = "proto3";

package debit_mandate;

service MandateRegistrationService {
    rpc RegisterMandate (MandateRegistrationRequest) returns (MandateActionResponse) {}
}

enum MandateCollectionFrequencyType {
    MANDATE_COLLECTION_FREQUENCY_TYPE_UNSPECIFIED = 0;
    MANDATE_COLLECTION_FREQUENCY_TYPE_DAILY = 1;
    MANDATE_COLLECTION_FREQUENCY_TYPE_WEEKLY = 2;
    MANDATE_COLLECTION_FREQUENCY_TYPE_MONTHLY = 3;
}

enum CurrencyCode {
    CURRENCY_CODE_UNSPECIFIED = 0;
    CURRENCY_CODE_EUR = 1;
}

message MoneyObject {
    CurrencyCode currency_code = 1;
    bool positive_value = 4;
    uint32 units = 2;
    uint32 nanos = 3;
}

message MandateRegistrationRequest {
    string debtor_name = 1;
    MandateCollectionFrequencyType collection_frequency = 2;
    MoneyObject instalment_amount = 3;
    string debtor_identity_number = 4;
    string bank_account_number = 5;
}

message MandateActionResponse {
    uint32 response_code = 1;
    string response_description = 2;
}

Enabling gRPC in Zato Projects

To use gRPC in your integration services, add the required dependencies to your project's requirements file:

# config/python-reqs/requirements.txt
grpcio>=1.50.0
grpcio-tools>=1.50.0
protobuf>=4.21.0

When your container starts, these dependencies will be automatically installed and available to your service.

Zato Service Integration

Create a Zato service that uses the gRPC client with proper input handling:

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

# stdlib
from dataclasses import dataclass

# Zato
from zato.server.service import Model, Service

# gRPC Code
from debit_mandate_pb2 import MANDATE_COLLECTION_FREQUENCY_TYPE_MONTHLY
from debit_mandate_client import MandateClient

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

@dataclass(init=False)
class MandateRegistrationRequest(Model):
    debtor_name: str
    debtor_identity_number: str
    bank_account_number: str
    collection_frequency: int
    amount_units: int

@dataclass(init=False)
class MandateRegistrationResponse(Model):
    status: int
    details: str

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

class MandateRegistrationService(Service):

    # Use API models
    input = MandateRegistrationRequest
    output = MandateRegistrationResponse

    def handle(self):

        # Local variables
        input = self.request.input

        # Get a client for the gRPC endpoint ..
        client = MandateClient()

        try:
            # .. invoke the endpoint ..
            grpc_response = client.register_mandate(
                debtor_name=input.debtor_name,
                debtor_identity_number=input.debtor_identity_number,
                bank_account_number=input.bank_account_number,
                collection_frequency=input.collection_frequency,
                amount_units=input.amount_units,
            )

            # .. map its response to ours ..
            response = MandateRegistrationResponse()
            response.status = grpc_response.response_code
            response.details = grpc_response.response_description

            # .. and return it to the caller.
            self.response.payload = response

        finally:
            client.close()

Testing the Integration

Once deployed, you can invoke your Zato service through a REST endpoint:

curl -X POST http://localhost:17010/api/mandate/register \
  -H "Content-Type: application/json" \
  -d '{
    "debtor_name": "John Doe",
    "debtor_identity_number": "123456789",
    "bank_account_number": "GB29NWBK60161331926819",
    "collection_frequency": 3,
    "amount_units": 100
  }'

The service returns a structured JSON response:

{"status": 200, "details": "Mandate registered successfully"}

More resources

➤ Python API integration tutorials
What is an integration platform?
Python Integration platform as a Service (iPaaS)
What is an Enterprise Service Bus (ESB)? What is SOA?
Open-source iPaaS in Python