REST in Python
Accept REST calls, react to HTTP verbs and invoke REST APIs from Python services.
REST channels expose your services as HTTPS endpoints and outgoing REST connections let your services call other APIs. Both are defined once, in the Dashboard or in enmasse, and your code refers to them by name.
Accept a REST call
The parsed JSON request is self.request.payload and whatever you assign to self.response.payload is serialized to JSON for the caller:
from zato.server.service import Service
class GetCustomer(Service):
input = 'customer_id'
output = 'customer_id', 'name', 'status'
def handle(self):
customer_id = self.request.input.customer_id
self.response.payload.customer_id = customer_id
self.response.payload.name = 'Jane Doe'
self.response.payload.status = 'active'
Invoke it:
React to HTTP verbs
Implement handle_<VERB> methods and each verb gets its own code path - a verb with no method receives 405 Method Not Allowed:
from zato.server.service import Service
class Customers(Service):
def handle_GET(self):
self.response.payload = {'customers': ['123', '456']}
def handle_POST(self):
customer = self.request.payload
self.logger.info('Creating customer: %s', customer['name'])
self.response.status_code = 201
Call a REST API
Look up an outgoing connection by name and call it with the verb you need - the payload, query parameters and headers are plain dicts and the response's JSON is already parsed in response.data:
from zato.server.service import Service
class SetBillingInfo(Service):
def handle(self):
payload = {'billing': '395.7', 'currency': 'EUR'}
params = {'cust_id': '39175', 'priority': 'normal'}
headers = {'X-App-Name': 'Zato'}
conn = self.rest['Billing API']
response = conn.post(self.cid, payload, params, headers=headers)
self.response.payload = response.data
The same connection object has .get, .put, .patch and .delete too, and response.status_code carries the HTTP status the API returned.
Path parameters
If the connection's URL path contains a pattern, e.g. /api/billing/{phone_no}, the matching key from params fills it in and the remaining keys go to the query string:
from zato.server.service import Service
class GetBillingInfo(Service):
def handle(self):
params = {'phone_no': '271637517', 'period': '2026-08'}
conn = self.rest['Billing API']
response = conn.get(self.cid, params=params)
self.response.payload = response.data
Configuration
The enmasse YAML for the channel and the outgoing connection the examples above use:
channel_rest:
- name: api.customers
service: get-customer
url_path: /api/customers
security: api.customers.key
outgoing_rest:
- name: Billing API
host: https://billing.example.com
url_path: /api/billing/{phone_no}
data_format: json
security: billing.bearer_token
See also
| Feature | What it does |
|---|---|
| REST channels | Every option of a channel, from URL matching to CORS |
| Calling REST APIs | Retries, timeouts, errors and responses of outgoing calls |
| Authentication | API keys, Basic Auth, OAuth and bearer tokens on both sides |
| Data models | Typed request and response contracts for REST services |