Skip to main content
Arupa uses one path-pattern implementation for Kernel access rules and plugin resource registration. The implementation lives in internal/netx/path.go and provides two operations:
  • ValidatePathPattern checks whether a pattern is valid; and
  • MatchPathPattern checks whether a request path matches that pattern.
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:
PatternMatchesDoes not match
/api/items/api/items/api/items/, /api/items/1
/health/health/healthz
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:
CallerRoot behavior
Route.Allow/ matches only /
Plugin HTTP route/ matches only /
Static directory mount/ matches every absolute path
The first two callers use RootPathExact. Static mounts use RootPathSubtree, so a static directory mounted at / can serve paths below the root.

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 plugin router selects an HTTP route or a static mount.

Host access rules

Route.Allow matches the request’s URL path before the request reaches a host handler or plugin 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.

Plugin HTTP routes

Plugins 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 plugins. A methodless route conflicts with every method at that same path.

Static mounts

Static directory mounts use subtree matching. The Kernel normalizes a directory mount to a pattern ending in /, so a mount configured at /assets serves the /assets/ subtree. Static file mounts use exact matching and must not end in /. A static file mount at /favicon.ico therefore serves that path only. Static mounts and plugin HTTP routes are both considered by the plugin router. The router chooses the longest matching pattern; when a static mount and HTTP route have the same matching length, the static mount is selected.