Path Composition

When a route belongs to a group, Vrata composes the group’s path with the route’s path to create the final match. The composition rules depend on the path types involved.

Composition table

Group pathRoute pathFinal matchType
pathPrefix: /api/v1pathPrefix: /productspathPrefix: /api/v1/productsPrefix + prefix
pathPrefix: /api/v1path: /healthpath: /api/v1/healthPrefix + exact
pathPrefix: /api/v1pathRegex: /[0-9]+pathRegex: ^/api/v1/[0-9]+Prefix + regex
pathPrefix: /api(no path)pathPrefix: /apiPrefix only
pathRegex: /(en|es)pathPrefix: /productspathRegex: (?:/(en|es))(?:/products)Regex + literal
pathRegex: /(en|es)pathRegex: /[0-9]+pathRegex: (?:/(en|es))(?:/[0-9]+)Regex + regex
pathRegex: /(en|es)path: /healthpathRegex: (?:/(en|es))(?:/health)Regex + literal
pathRegex: /(en|es)(no path)pathRegex: /(en|es)Regex only

When a group uses pathRegex and a route uses a literal path (path or pathPrefix), the literal is escaped with regexp.QuoteMeta before composition. This prevents accidentally breaking the regex.

Examples

API versioning

Group:

{"name": "api-v1", "pathPrefix": "/api/v1", "routeIds": ["products", "orders"]}

Route products:

{"name": "products", "match": {"pathPrefix": "/products"}}

Route orders:

{"name": "orders", "match": {"pathPrefix": "/orders"}}

Final routing table:

Multi-language prefix

Group:

{"name": "i18n", "pathRegex": "/(en|es|fr|de)", "routeIds": ["store", "checkout"]}

Route store:

{"name": "store", "match": {"pathPrefix": "/store"}}

Final routing table:

Hostname + path grouping

Group:

{
  "name": "public-api",
  "pathPrefix": "/api",
  "hostnames": ["api.example.com", "api.staging.example.com"],
  "routeIds": ["users", "health"]
}

Route users:

{"name": "users", "match": {"pathPrefix": "/users", "methods": ["GET", "POST"]}}

Route health:

{"name": "health", "match": {"path": "/health"}}

Final routing table:

Header matching from group

{
  "name": "v2-tenants",
  "pathPrefix": "/api",
  "headers": [{"name": "X-API-Version", "value": "2"}],
  "routeIds": ["users"]
}

Route users only matches when the group’s X-API-Version: 2 header is also present.

Hostnames

Hostnames from the group and the route are merged (union). There’s no limit on the number of hostnames.

{"name": "group", "hostnames": ["a.example.com"], "routeIds": ["route"]}

Route:

{"name": "route", "match": {"hostnames": ["b.example.com"]}}

Final match: hostnames ["a.example.com", "b.example.com"].

Headers

Header matchers from the group and route are also merged. All headers must match.