Routers
Routing implementations for genro-asgi.
StaticRouter
Filesystem-backed router for serving static files.
StaticRouter - Storage-backed router with best-match path resolution.
Maps URL paths to storage nodes (files or directories). Uses best-match strategy: walks the path as far as possible, returns the deepest valid node with unconsumed segments as extra_args.
Implements RouterInterface for use in routing hierarchies.
- Best-Match Resolution:
Given path “alfa/beta/gamma/123?xx=3” and filesystem with only alfa/beta/:
Walk: alfa (exists) → beta (exists) → gamma (not found) → STOP
Return: StaticRouterNode pointing to alfa/beta/
extra_args: [“gamma”, “123”]
partial_kwargs: {“xx”: “3”}
The caller decides what to do with extra_args (e.g., pass to handler, use for sub-routing, return 404, etc.)
- Usage:
# Create router from storage node router = StaticRouter(storage.node(“site:static”))
# Resolve exact file router_node = router.node(“css/style.css”) storage_node = router_node() # StorageNode for style.css content = storage_node.read_bytes()
# Resolve with best-match (partial path) router_node = router.node(“docs/api/v2/users?format=json”) # If only docs/api/ exists: storage_node = router_node() # StorageNode for docs/api/ extra = router_node.extra_args # [“v2”, “users”] params = router_node.partial_kwargs # {“format”: “json”}
# Check node type if router_node.metadata[“isfile”]:
# Serve file content pass
- elif router_node.metadata[“isdir”]:
# Directory - caller decides (list, index.html, pass to handler) pass
- StaticRouterNode Attributes:
type: “entry” (file) or “router” (directory)
name: basename of the storage node
path: resolved path (consumed segments)
callable: the node itself (for compatibility)
extra_args: list of unconsumed path segments
partial_kwargs: dict from parsed query string
metadata: {“mime_type”: str, “isdir”: bool, “isfile”: bool}
- class genro_asgi.routers.static_router.StaticRouter(root, name=None, *, html_index=True)[source]
Bases:
RouterInterfaceStorage-backed router with best-match resolution.
Wraps a StorageNode (filesystem, S3, HTTP, etc.) and resolves paths using best-match strategy. Returns RouterNode whose callable yields the underlying StorageNode.
- name
Router name for introspection (optional)
- __init__(root, name=None, *, html_index=True)[source]
Initialize router with a storage root.
- Parameters:
root (
StorageNode) – StorageNode pointing to the directory to serve.name (
str|None) – Optional name for introspection and debugging.html_index (
bool) – Reserved for future use (index.html resolution).
- node(path, **kwargs)[source]
Resolve path using best-match strategy.
Walks path segment by segment until a non-existent node is found. Returns the deepest valid node with unconsumed segments in extra_args.
- Parameters:
path (
str) – Relative path, optionally with query string. Examples: “css/style.css”, “api/v2/users?limit=10”- Returns:
callable() → StorageNode (the resolved file or directory)
extra_args: list of path segments after the resolved node
partial_kwargs: dict parsed from query string
type: “entry” (file) or “router” (directory)
metadata: {“mime_type”, “isdir”, “isfile”}
None if root doesn’t exist.
- Return type:
Examples
# Exact file match node = router.node(“style.css”) node.extra_args # [] node() # StorageNode for style.css
# Partial match with extra segments node = router.node(“docs/api/v2/users”) # If only docs/api/ exists: node.extra_args # [“v2”, “users”] node() # StorageNode for docs/api/
# With query string node = router.node(“data?format=json&limit=10”) node.partial_kwargs # {“format”: “json”, “limit”: “10”}
- nodes(basepath=None, lazy=False, mode=None, pattern=None, **kwargs)[source]
Return a tree of files/directories respecting filters.
- Parameters:
basepath (
str|None) – Path to start from (e.g., “images/icons”). If provided, returns nodes starting from that point.lazy (
bool) – If True, child directories are returned as callables instead of recursively expanded.mode (
str|None) – Output format mode (reserved for compatibility).pattern (
str|None) – Regex pattern to filter entry names. Only files whose name matches are included.
- Returns:
name, description, router, entries, routers. Empty dict if root doesn’t exist or is empty.
- Return type:
- class genro_asgi.routers.static_router.StaticRouterNode(storage_node, node_type, name, path, extra_args, partial_kwargs, metadata)[source]
Bases:
objectMinimal RouterNode for StaticRouter. Returns StorageNode on __call__.
- type
“entry” (file) or “router” (directory)
- name
basename of the storage node
- path
resolved path (consumed segments)
- callable
self (for compatibility with tests expecting .callable)
- extra_args
list of unconsumed path segments
- partial_kwargs
dict from parsed query string
- metadata
{“mime_type”: str, “isdir”: bool, “isfile”: bool}
- property callable: StaticRouterNode
Return self for compatibility with code expecting .callable attribute.
- extra_args
- metadata
- name
- partial_kwargs
- path
- type