Skip to main content
Arupa uses one path-pattern implementation for Kernel access rules and service route registration. This is a small path-pattern language. It is not a wildcard, glob, or regular expression matcher.

Valid patterns

A pattern must:
  • be non-empty; and
  • start with /.
Use a trailing / when you want to match a path subtree:
Characters such as * or ? do not create wildcard behavior. Unless the pattern ends in /, the entire pattern is compared as a literal path.

Matching rules

Exact paths

A pattern that does not end in / matches only the same path: The trailing slash is significant. /api/items and /api/items/ are different exact paths.

Subtrees

A pattern ending in / matches paths that begin with that pattern:
The parent path without the trailing slash is not part of the subtree. If you need both /api and its children, define separate patterns.

The root path

/ is handled specially because different resource types use it differently: Most callers use RootPathExact. A directory-backed static route and a proxy route both use RootPathSubtree, so either one mounted at / can serve or forward paths below the root — useful when a proxy should own the whole application, or a static directory should provide its general content.

Choosing between matching patterns

When several patterns match a path, Arupa selects the longest matching pattern. It does not merge the rules or group lists from all matching patterns. For example, given these host access rules:
/api/admin/users matches both patterns, but /api/admin/ wins because it is longer. Only the root group rule is evaluated for that request. This same longest-pattern rule is used when the service router selects an HTTP route, whether that route serves packaged files through a static transport or is handled dynamically.

Host access rules

Route.Allow matches the request’s URL path before the request reaches a host handler or service handler. Configuration validation applies the same pattern rules described above. See Access control for how the selected route’s group list is evaluated against the authenticated user. The query string is not part of path matching. For example, a request for /api/items?limit=10 is matched using /api/items.

Service HTTP routes

Services use the same path patterns when they register HTTP routes. After the router selects the longest matching path pattern, it selects a handler by HTTP method:
  • an explicitly declared method such as GET or POST is matched case-insensitively after normalization;
  • an empty method is a handler for any method; and
  • an explicit method takes precedence over an empty-method handler for the selected path.
If a path matches but no registered method matches, Arupa returns 405 Method Not Allowed and includes the available methods in the Allow response header. Routes with the same path and conflicting methods cannot be registered by different services. A methodless route conflicts with every method at that same path. This section covers how a path is matched once a route exists. For how a route is declared and bound to a transport — including the static transport that serves packaged files without running service code — see Routes and transports.

Reserved paths

Before any service registers a route, the Kernel reserves a fixed set of HTTP paths for itself — the paths behind login and the whole Management API:
A path without a trailing slash reserves that exact path only, matching the collection-level endpoint for that capability (GET /api/user, GET /api/service, and so on). A path ending in / reserves that pattern as a subtree route, covering the nested per-resource endpoints under it (/api/user/{name}, /api/service/config/{name}, and so on) — see Subtrees for what that pattern shape means. These reservations go through the same router services use, so a service cannot register an HTTP route at exactly one of these patterns; the attempt fails the same way it would against a path another service already owns. Only paths implemented directly by the Kernel are reserved this way — everything else, including the pages a core service such as login serves, competes for path ownership like any other service route. A capability being reserved has nothing to do with whether it’s enabled. The Kernel claims these paths at startup regardless of the [API] table, so a service can never register a route that would collide with a capability’s endpoints even while that capability is turned off; see Management API for how the enabled/disabled state itself is enforced. This list is defined by the Kernel and may grow in future versions; treat it as the set of paths no service can claim, rather than a fixed, permanent list.

Static routes

A route bound to a static transport uses the same path-pattern rules as any other HTTP route, with one addition: whether it matches as an exact path or a subtree depends on whether its source is a single file or a directory.
  • A route backed by a directory source uses subtree matching. The Kernel normalizes it to a pattern ending in /, so a route configured at /assets serves the /assets/ subtree.
  • A route backed by a single-file source uses exact matching and must not end in /. A route at /favicon.ico therefore serves that path only.
Static and dynamically handled routes are both considered by the same service router and compete for the same path space. The router chooses the longest matching pattern; when a static route and a dynamically handled route have the same matching length, the static route is selected. See Routes and transports for the full conflict rules, including how a batch of route registrations is applied.