SOA and REST hand in hand - reusable RESTful HTTP channels in Zato 2.0
Overview
It has been possible to create reusable REST services in Zato right from the release 1.0 however a feature that recently landed in GitHub and that will be released in Zato 2.0 makes it easier to use of RESTful URLs, also known as clean URLs.
This blog post presents HTTP channels and an upcoming one will deal with HTTP outgoing connections.
The goal
The diagram below depicts what we’d like to achieve - 3 independent applications invoking the same service yet each using separate URLs. To keep it simple, let’s say we want to return a customer’s order in JSON.
- App1 uses GET and URL in format of /app1/customer/{cid}/order/{oid}
- App2 uses POST to send JSON with customer ID while the order ID is in the URL /app2/order_id{oid}
- App3 uses GET and sends parameters in query string, e.g. /app3?cid=111&oid=222 Each of them should invoke the same reusable service that should receive parameters on input without any changes to the code regardless of which application invokes it.

Service code
This is how the service we’re exposing will look like. Note that for clarity, the same response is always produced though input data is copied over so we can quickly confirm on command line they were indeed received by the service.
Also note that we make use of SimpleIO - a declarative syntax for expressing I/O parameters that lets one use Python dictionaries, bunches or SQLAlchemy objects directly in order to forget about manual serialization - no matter if it’s JSON or XML/SOAP, though only the former is used in this post.
# Zato
from zato.server.service import Service
class GetOrder(Service):
""" Returns details of a given order.
"""
class SimpleIO:
input_required = ('cid', 'oid')
output_required = ('cid', 'oid', 'value', 'date')
def handle(self):
# Copy over from request
self.response.payload.cid = self.request.input.cid
self.response.payload.oid = self.request.input.oid
# Dummy order details
self.response.payload.value = 11223344
self.response.payload.date = '2013-10-27'
# An appropriate content type for the payload returned
self.response.content_type = 'application/x-order-details'
The service can be hot-deployed in the cluster and we can expose it through channels.
Channels
3 separate HTTP channels for each of the applications.



INVOKING FROM COMMAND LINE
Having deployed the service and created the channels, we can proceed to invoking the services. Note that no restarts are required.
JSON output has been slightly reformatted for clarity.
APP1
$ curl localhost:11223/app1/customer/11/order/22
{
"response": {
"cid": "11",
"oid": "22",
"value": 11223344,
"date": "2013-10-27"
}
}
APP2
$ curl localhost:11223/app2/order_id44 -d '{"cid":"33"}'
{
"response": {
"cid": "33",
"oid": "44",
"value": 11223344,
"date": "2013-10-27"
}
}
APP3
$ curl "localhost:11223/app3?cid=55&oid=66"
{
"response": {
"cid": "55",
"oid": "66",
"value": 11223344,
"date": "2013-10-27"
}
}
A NOTE ON INVOKING
We couldn’t use the built-in service invoker GUI as this bypasses channels altogether and while it is in fact a great help in development, it can’t really be used here when the gist of the matter are channels themselves.
TWEAKING
How URL parameters are handled is governed by 3 options each channel offers:
Option | Notes |
---|---|
Merge URL params to req | Whether parameters found in URL, no matter if path or query string, should be included in sel |
URL params priority | What to do if parameters in path conflict with query string ones, i.e. what wins if both are |
provided, such as in /customer/123/?cid=456 | |
Params priority | After obtaining parameters from URL (taking their relative priority into account), |
how to resolve conflicts if both the URL and request body contain the same parameter, | |
which one has higher priority |
Conclusion
RESTful channels expand means through which reusable Zato-based services can be exposed to external applications. The feature is slated for inclusion in 2.0 and is already available from GitHub, in the master branch.