HTTP Method and Accept headers

Zato 3.1 includes new means to manage access to REST services based on input Method and Accept headers in HTTP requests - here is how they can be employed in practice.

A bit of background

Prior to Zato 3.1, one could always build a REST API reacting to individual HTTP verbs by implementing handle_VERB methods in services, such as:

class MyService(Service):

    def handle_GET(self):
        # Reacts to GET requests
        pass

    def handle_POST(self):
        # Reacts to POST requests
        pass

    # Any other handle_VERB method will be used accordingly

This works and will continue to work as expected in all future Zato versions.

However, one aspect of it is that, if one uses SimpleIO, keeping all handler methods in the same service means that all of them share the same SIO definition which is not always desirable - for instance, input to POST may be unrelated to input that DELETE receives.

REST channel URL paths

In Zato 3.1 and newer, it is possible to create REST channels that have the same URL path but different services mounted on each channel, separately for each HTTP verb requires.

That is, whereas previously it was a single service with multiple handle_VERB methods, now it can be a set of services, each reacting to a different HTTP verb and all of them mounted on the same URL path.

In a way, this was supported previously but, if handle_VERB methods were not used, URL paths had to be distinct, e.g.

GET /api/user
DELETE /api/user/delete
POST /api/user/create

In 3.1+, this can be simplified to:

GET /api/user
DELETE /api/user
POST /api/user

Now, each of the combination of verb + path may be unique for a REST channel while previously each channel needed to have its own URL path.

Moreover, because each channel may have its own separate service, it also means that each service may have its own SimpleIO definition and that the service becomes less tied to REST.

HTTP Accept headers

This is a completely new feature in 3.1 which lets one have distinct REST channels depending on the requests's Accept headers.

For instance, let's say that we would like to process incoming invoices under POST /api/invoice but we would like to have two services reacting to the same endpoint, one for JSON and now for PDF invoices.

This can be achieved by configuring HTTP Accept headers in their channels, as below - note that the method and URL path are the same in both cases yet HTTP Accept and services are different because each service reacts to a different value of HTTP Accept:

HTTP Accept header patterns

We can go one better and take advantage of Accept header patterns - with an asterisk meaning any character - this will configure the channel to process requests matching any value that fits in with the pattern, e.g. text/ will mean text/csv, text/xml or anything that starts with text/*.

However, seeing as it can be a number of input MIME types, at this point we may need to know what the actual value was - this can be extracted from the WSGI environment via self.wsgi_environ.

Summary

Zato 3.1 saw improvements and backward-compatible changes to how REST channels can be built.

It will now support more use-cases, such as single URL path channels with different HTTP verbs and independent SimpleIO definitions or HTTP Accept headers different for each channel.

In turn, this lets one build REST APIs that are more flexible and elastic in their design to react to different input criteria.