Request and response objects


Request and response objects encapsulate information regarding the data a service receives and produces. Both objects will always exist for each service invocation but their payload can be empty, it’s perfectly fine for a service not to accept any input data nor to create output either.

There are also other complementing attributes and methods a service has access to.

Save the following code in and hot-deploy it - this will be the service that will be modified later in the chapter.

You’ll also need to create a new plain HTTP channel so that the service can be easily accessed through curl.

from zato.server.service import Service

class MyService(Service):
    def handle(self):


An instance of zato.server.service.Request class, each service's self.request provides access to several interesting attributes regarding the input data.


As an aid during development and debugging, a service can log its input using the log_input method.

Attribute Datatype Notes
input SIO A Simple IO payload object which allows to directly address request elements regardless of the data format. Will be behave like an empty dictionary if the service doesn't use SIO.
raw_request string or a Python object

Represents the request message exactly as it was received by Zato, prior to having been parsed, if at all.

Always available regardless of the data format and whether SIO was used or not.

With channels, raw_request will be an empty string if there was no input data at all

If a service was invoked directly, it will be a Python object received on input, such as a list or dict.

payload (depends)

If data_format is JSON and channel is a plain HTTP one, the incoming JSON document as a Python dictionary.

If data_format is XML and channel is a plain HTTP one, the root element of the document, an instance of lxml.objectify.ObjectifiedElement

If data_format is XML and channel is a SOAP one, first child of /soapenv:Envelope/soapenv:Body returned as an instance of lxml.objectify.ObjectifiedElement

In all other cases, in particular - when using other data formats - this will be equal to raw_request.


Looking for HTTP request headers? They're part of the WSGI environment a service receives.


An instance of zato.server.service.Response class, self.response attribute of each service instance influences what the application invoking a service will receive.

Attribute   Notes

A service can assign output parameters directly to payload if SIO is used.

In any other case, payload must be assigned a string containing the response.

result   Defaults to ZATO_OK and must be either ZATO_OK or ZATO_ERROR from zato.common. If the latter, an exception will be raised and signalled to the calling invocation in a transport-specific way, e.g. using a Fault message for SOAP channels. A proper status_code will be returned too.
result_details   If result is ZATO_ERROR, any details the client application should receive.

HTTP only. Value of the Content-Type header to return. Sane defaults are used:

  • 'application/json' for JSON channels
  • 'application/xml' for Plain HTTP channels with XML data format
  • 'application/xml' for SOAP 1.1
  • 'application/soap+xml; charset=utf-8' for SOAP 1.2
headers   HTTP only. A dictionary of headers you'd like for the service to return.
status_code   HTTP only. Status code a service returns. Must be one of the responses httplib defines. Defaults to httplib.OK


As an aid during development and debugging, a service can log its output using the log_output method.

Setting HTTP response headers

Below is an example of how one can affect the exact HTTP headers a service will return.

You can also visit http://localhost:17010/ in your browser.

# stdlib
import httplib

# Zato
from zato.server.service import Service

class MyService(Service):

    def handle(self):
        self.response.status_code = httplib.OK # Same as default
        self.response.payload = 'welcome,to,Zato'
        self.response.content_type = 'text/csv'
        self.response.headers['X-Welcome'] = 'Happy coding! :-)'
        self.response.headers['Content-Disposition'] = 'attachment; filename=info.csv'
$ curl localhost:17010/
$ curl -v localhost:17010/
* About to connect() to localhost port 17010 (#0)
*   Trying connected
> GET / HTTP/1.1
> User-Agent: curl/7.22.0
> Host: localhost:17010
> Accept: */*
< HTTP/1.1 200 OK
< Server: gunicorn/0.16.1
< Date: Tue, 19 Feb 2013 10:39:57 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
< Content-Type: text/csv
< X-Welcome: Happy coding! :-)
< Content-Disposition: attachment; filename=info.csv
* Connection #0 to host localhost left intact
* Closing connection #0

More information