URL path matching

How a request finds its channel - path parameters, methods, Accept headers and match priorities.

A request is routed to a channel by three things - its URL path, its HTTP method and its Accept header. This page covers how each is matched, what happens when several channels match one request, and every option that shapes the outcome.

Before matching starts

The server accepts these HTTP methods: GET, POST, DELETE, PUT, PATCH, HEAD, OPTIONS. A request with any other method is answered 405 before URL matching runs.

Path parameters

Curly braces in a channel's URL path capture parameters:

/api/customers/{customer_id}/orders/{order_id}

Each parameter matches one or more characters from this set: letters, digits and underscore, plus $ . - : | = ~ ^ % @ + , ; ! ( ) and space. The captured values reach your service as self.request.http.params:

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

# Zato
from zato.server.service import Service

class GetOrder(Service):

    name = 'demo.rest.get-order'

    def handle(self) -> 'None':

        customer_id = self.request.http.params['customer_id']
        order_id = self.request.http.params['order_id']

self.request.http.params holds path parameters only. Query string values are in self.request.http.GET - a single-valued key points at its value directly and a repeated key at a list of values.

The match_slash option

By default a path parameter can also match slashes, so {path} in /files/{path} matches reports/2026/summary.csv in one parameter. Turning match_slash off on the channel makes each parameter stop at the next slash, so one parameter is one path segment.

Method and Accept matching

A channel may name one HTTP method, in which case only that method reaches it, or leave the method empty to accept any method the server allows. Likewise a channel may name an Accept value through its http_accept option - a channel configured with */* or nothing accepts any Accept header.

When several channels match

Two channels may share a URL path as long as they differ in HTTP method or in their http_accept value. Creating a channel whose path, method and Accept value all equal an existing channel's fails with an error naming that other channel.

A create also fails when two channels would match the same requests with equal specificity but different security - the error names both channels and states that they secure the same requests differently.

When several channels legitimately match one request, the most specific one wins. Specificity is decided in order by the longest literal path prefix, the total literal length of the path, whether the channel names an Accept value, and whether it names a method.

Parameter priorities

Two settings on the channel decide how parameters merge:

  • url_params_pri - when one name appears both in the path and in the query string, qs-over-path (the default) lets the query string win and path-over-qs lets the path parameter win.
  • merge_url_params_req - on by default. When on, path and query parameters are merged into self.request.input for keys the payload does not already contain, and self.request.http.GET and self.request.http.POST are populated. When off, none of that happens and only the payload reaches the service.

When self.request.http.POST is populated

self.request.http.POST is filled in two cases, both requiring merge_url_params_req to be on:

  • The channel's data format is form and the request's content type is application/x-www-form-urlencoded or multipart/form-data - the parsed form is both POST and the service's payload
  • The channel has no data format at all, in which case the raw body is parsed as a query string into POST

A channel with any other data format, JSON included, leaves POST empty.

Data format

A new channel has no default data format - a channel that should parse JSON bodies into self.request.payload must set its data format to JSON explicitly, in the Dashboard or in enmasse YAML. Without it, the service receives the raw request bytes.

The match cache

Resolved matches are kept in a least-recently-used cache of 10,000 entries, with a second cache of the same size for paths that matched nothing. Both are transparent - any channel create, edit or delete evicts the affected entries. The bound matters only for channels with high-cardinality dynamic paths, where more than 10,000 distinct URLs rotate through the cache.

An inactive channel

An inactive channel stays in the routing table but answers every request with 404, the same status a caller sees when no channel exists at all - deactivation is indistinguishable from absence on purpose.

See also

PageWhat it covers
REST channelsCreating channels and reading parameters in services
HTTP verbsOne service responding differently to GET, POST, PUT, PATCH and DELETE
Error catalogEvery status code a channel returns, including 404 and 405
Enmasse referencematch_slash, http_accept and every other channel_rest key in YAML

Learn more