Build messages in Python

Build nested messages and responses through plain dot access.

Messages in Zato are built through plain dot access - you assign attributes and nested structures appear on their own, with no declarations, no dictionaries to pre-build and no classes to define first.

The same pattern works everywhere a message is produced: standalone objects, service responses and SOAP requests alike.

Standalone messages

A Message is a dynamic object - assigning to any attribute path creates the whole path in one go:

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

# Zato
from zato.common import Message

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

msg = Message()

msg.customer.name = 'John Doe'
msg.customer.address.city = 'Amsterdam'
msg.customer.address.country = 'Netherlands'

Calling to_dict returns the tree as a plain dict, in the order the fields were assigned in:

msg.to_dict()
{"customer": {"name": "John Doe", "address": {"city": "Amsterdam", "country": "Netherlands"}}}

Assigning a list means repeated elements, and the list may contain scalars and messages alike:

line1 = Message()
line1.product = 'ABC'
line1.quantity = 3

line2 = Message()
line2.product = 'DEF'
line2.quantity = 7

msg = Message()
msg.order.lines = [line1, line2]
{"order": {"lines": [{"product": "ABC", "quantity": 3}, {"product": "DEF", "quantity": 7}]}}

Messages as responses

A message built anywhere in your code can be assigned to self.response.payload as a whole and it serializes to the channel's data format automatically:

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

# Zato
from zato.common import Message
from zato.server.service import Service

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

class GetCustomer(Service):

    name = 'example.messages.get-customer'

    def handle(self) -> 'None':

        msg = Message()
        msg.customer.name = 'John Doe'
        msg.customer.address.city = 'Amsterdam'

        self.response.payload = msg

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

Zero-declaration responses

Most of the time you don't even need a standalone object - self.response.payload is already a message, so a service with no input or output declarations at all builds its response through the same dot access directly:

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

# Zato
from zato.server.service import Service

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

class GetCustomer(Service):

    name = 'example.messages.get-customer'

    def handle(self) -> 'None':

        self.response.payload.customer.name = 'John Doe'
        self.response.payload.customer.address.city = 'Amsterdam'

# ###############################################################################
{"customer": {"name": "John Doe", "address": {"city": "Amsterdam"}}}

If you prefer to pin the shape of your responses down, declare output names or data models and the payload will follow them - the request and response chapter covers all three cases.

SOAP

Behind SOAP channels, the very same dot access builds SOAP messages - you assign attributes to a SOAPMessage, the channel takes care of the envelope, and you never touch XML at all. The SOAP tutorial shows the whole flow.

See also

FeatureWhat it does
Request and responseEverything about self.request.input and self.response.payload
Data modelsPin your API's shape down, validated and documented
Config tablesTranslate the codes a message carries between parties

Learn more