Skip to content

Router Classes

The router system provides powerful routing capabilities including subrouting and modular route organization.

Router

Router

Router(prefix: str = '')

Router class for handling route registration and resolution.

Provides methods for registering routes with different HTTP methods, mounting subrouters, and resolving incoming requests to appropriate handlers.

Parameters:

Name Type Description Default
prefix str

Optional path prefix for all routes in this router

''

Attributes:

Name Type Description
prefix

Path prefix for this router

routes dict[str, dict[str, Route]]

Dictionary of registered routes

subrouters dict[str, Router]

Dictionary of mounted subrouters

Source code in src/artanis/routing.py
def __init__(self, prefix: str = "") -> None:
    self.prefix = prefix.rstrip("/")
    self.routes: dict[str, dict[str, Route]] = {}
    self.subrouters: dict[str, Router] = {}
    self.logger = logger

Functions

all
all(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a route that responds to all HTTP methods.

This registers the handler for all standard HTTP methods (GET, POST, PUT, DELETE, PATCH, OPTIONS).

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Example
# Middleware that runs for all methods
def auth_middleware(request, user_id):
    # Authenticate user for any HTTP method
    return {"user_id": user_id, "authenticated": True}

router.all("/users/{user_id}", auth_middleware)
Source code in src/artanis/routing.py
def all(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a route that responds to all HTTP methods.

    This registers the handler for all standard HTTP methods
    (GET, POST, PUT, DELETE, PATCH, OPTIONS).

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware

    Example:
        ```python
        # Middleware that runs for all methods
        def auth_middleware(request, user_id):
            # Authenticate user for any HTTP method
            return {"user_id": user_id, "authenticated": True}

        router.all("/users/{user_id}", auth_middleware)
        ```
    """
    methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
    for method in methods:
        self.register_route(method, path, handler, middleware)
delete
delete(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a DELETE route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def delete(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a DELETE route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("DELETE", path, handler, middleware)
find_route
find_route(
    method: str, path: str
) -> tuple[Route | None, dict[str, str], Router | None]

Find a route handler and extract path parameters.

Parameters:

Name Type Description Default
method str

HTTP method

required
path str

Request path

required

Returns:

Type Description
tuple[Route | None, dict[str, str], Router | None]

Tuple of (route, path_parameters, source_router) or (None, {}, None) if not found

Source code in src/artanis/routing.py
def find_route(
    self, method: str, path: str
) -> tuple[Route | None, dict[str, str], Router | None]:
    """Find a route handler and extract path parameters.

    Args:
        method: HTTP method
        path: Request path

    Returns:
        Tuple of (route, path_parameters, source_router) or (None, {}, None) if not found
    """
    method = method.upper()

    # First, try direct routes in this router
    for methods in self.routes.values():
        if method in methods:
            route = methods[method]
            params = route.match(path)
            if params is not None:
                return route, params, self

    # Then, try subrouters
    for mount_path, subrouter in self.subrouters.items():
        if "{" in mount_path:
            # Handle parameterized mount paths
            mount_route = Route("GET", mount_path, lambda: None)

            # Try to match the mount pattern against the beginning of the path
            # We need to check if the path can be split into mount + sub parts
            mount_pattern = mount_route.pattern.pattern
            # Remove only the start ^ and end $ anchors, not ^ inside character classes
            if mount_pattern.startswith("^"):
                partial_pattern = mount_pattern[1:]
            else:
                partial_pattern = mount_pattern
            if partial_pattern.endswith("$"):
                partial_pattern = partial_pattern[:-1]

            import re

            # Try to match from start of path
            match = re.match(partial_pattern, path)
            if match:
                mount_params = match.groupdict()
                matched_length = match.end()

                # Extract remaining path for subrouter
                sub_path = path[matched_length:]
                if not sub_path:
                    sub_path = "/"
                elif not sub_path.startswith("/"):
                    sub_path = "/" + sub_path

                # Recursively search in subrouter
                sub_route, sub_params, source_router = subrouter.find_route(
                    method, sub_path
                )
                if sub_route is not None:
                    # Merge mount parameters with subroute parameters
                    all_params = {**mount_params, **sub_params}
                    return sub_route, all_params, source_router
        # Simple mount path (no parameters)
        elif path.startswith(mount_path):
            if mount_path == "/":
                sub_path = path
            else:
                sub_path = path[len(mount_path) :]
                if not sub_path:
                    sub_path = "/"
                elif not sub_path.startswith("/"):
                    sub_path = "/" + sub_path

            # Recursively search in subrouter
            sub_route, sub_params, source_router = subrouter.find_route(
                method, sub_path
            )
            if sub_route is not None:
                return sub_route, sub_params, source_router

    return None, {}, None
get
get(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a GET route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def get(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a GET route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("GET", path, handler, middleware)
get_all_routes
get_all_routes() -> list[dict[str, Any]]

Get all routes from this router and subrouters.

Returns:

Type Description
list[dict[str, Any]]

List of all route dictionaries

Source code in src/artanis/routing.py
def get_all_routes(self) -> list[dict[str, Any]]:
    """Get all routes from this router and subrouters.

    Returns:
        List of all route dictionaries
    """
    all_routes = []

    # Add direct routes
    for methods in self.routes.values():
        for route in methods.values():
            all_routes.append(route.to_dict())

    # Add subrouter routes with proper path prefixes
    for mount_path, subrouter in self.subrouters.items():
        subrouter_routes = subrouter.get_all_routes()
        for route_dict in subrouter_routes:
            # Update the path to include the mount prefix
            original_path = route_dict["path"]
            if mount_path == "/":
                full_path = original_path
            elif original_path == "/":
                full_path = mount_path
            else:
                full_path = mount_path + original_path

            # Create a new route dict with updated path
            updated_route = route_dict.copy()
            updated_route["path"] = full_path
            all_routes.append(updated_route)

    return all_routes
get_allowed_methods
get_allowed_methods(path: str) -> list[str]

Get allowed HTTP methods for a given path.

Parameters:

Name Type Description Default
path str

Request path

required

Returns:

Type Description
list[str]

List of allowed HTTP methods

Source code in src/artanis/routing.py
def get_allowed_methods(self, path: str) -> list[str]:
    """Get allowed HTTP methods for a given path.

    Args:
        path: Request path

    Returns:
        List of allowed HTTP methods
    """
    allowed_methods = []

    # Check direct routes
    for methods in self.routes.values():
        for route in methods.values():
            if route.match(path) is not None:
                allowed_methods.append(route.method)

    # Check subrouters
    for mount_path, subrouter in self.subrouters.items():
        if path.startswith(mount_path):
            if mount_path == "/":
                sub_path = path
            else:
                sub_path = path[len(mount_path) :]
                if not sub_path.startswith("/"):
                    sub_path = "/" + sub_path

            allowed_methods.extend(subrouter.get_allowed_methods(sub_path))

    return list(set(allowed_methods))  # Remove duplicates
mount
mount(path: str, router: Router) -> None

Mount a subrouter at the specified path.

Parameters:

Name Type Description Default
path str

Path prefix where the subrouter should be mounted

required
router Router

Router instance to mount

required
Source code in src/artanis/routing.py
def mount(self, path: str, router: Router) -> None:
    """Mount a subrouter at the specified path.

    Args:
        path: Path prefix where the subrouter should be mounted
        router: Router instance to mount
    """
    normalized_path = self._normalize_path(path)

    # Update subrouter's prefix
    router.prefix = normalized_path

    # Store subrouter
    self.subrouters[normalized_path] = router

    self.logger.debug(f"Mounted subrouter at: {normalized_path}")
options
options(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register an OPTIONS route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def options(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register an OPTIONS route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("OPTIONS", path, handler, middleware)
patch
patch(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a PATCH route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def patch(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a PATCH route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("PATCH", path, handler, middleware)
post
post(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a POST route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def post(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a POST route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("POST", path, handler, middleware)
put
put(
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a PUT route.

Parameters:

Name Type Description Default
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def put(
    self,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a PUT route.

    Args:
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    self.register_route("PUT", path, handler, middleware)
register_route
register_route(
    method: str,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None

Register a route with the router.

Parameters:

Name Type Description Default
method str

HTTP method

required
path str

URL path pattern

required
handler Callable[..., Any]

Route handler function

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None
Source code in src/artanis/routing.py
def register_route(
    self,
    method: str,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    """Register a route with the router.

    Args:
        method: HTTP method
        path: URL path pattern
        handler: Route handler function
        middleware: Optional route-specific middleware
    """
    # Normalize path
    full_path = self._normalize_path(path)

    if full_path not in self.routes:
        self.routes[full_path] = {}

    route = Route(method, full_path, handler, middleware)
    self.routes[full_path][method.upper()] = route

    self.logger.debug(f"Registered {method.upper()} route: {full_path}")

Route

Route

Route(
    method: str,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
)

Represents a single route with its handler and metadata.

Parameters:

Name Type Description Default
method str

HTTP method (GET, POST, PUT, DELETE, etc.)

required
path str

URL path pattern with optional parameters

required
handler Callable[..., Any]

Route handler function or coroutine

required
middleware list[Callable[..., Any]] | None

Optional route-specific middleware

None

Attributes:

Name Type Description
method

HTTP method

path

URL path pattern

handler

Route handler function

pattern

Compiled regex pattern for path matching

middleware

Route-specific middleware

Source code in src/artanis/routing.py
def __init__(
    self,
    method: str,
    path: str,
    handler: Callable[..., Any],
    middleware: list[Callable[..., Any]] | None = None,
) -> None:
    self.method = method.upper()
    self.path = path
    self.handler = handler
    self.pattern = self._compile_path_pattern(path)
    self.middleware = middleware or []

Functions

match
match(path: str) -> dict[str, str] | None

Check if this route matches the given path.

Parameters:

Name Type Description Default
path str

URL path to match against

required

Returns:

Type Description
dict[str, str] | None

Dictionary of extracted path parameters if match, None otherwise

Source code in src/artanis/routing.py
def match(self, path: str) -> dict[str, str] | None:
    """Check if this route matches the given path.

    Args:
        path: URL path to match against

    Returns:
        Dictionary of extracted path parameters if match, None otherwise
    """
    match = self.pattern.match(path)
    return match.groupdict() if match else None
to_dict
to_dict() -> dict[str, Any]

Convert route to dictionary for compatibility.

Returns:

Type Description
dict[str, Any]

Dictionary representation of the route

Source code in src/artanis/routing.py
def to_dict(self) -> dict[str, Any]:
    """Convert route to dictionary for compatibility.

    Returns:
        Dictionary representation of the route
    """
    return {
        "handler": self.handler,
        "method": self.method,
        "path": self.path,
        "pattern": self.pattern,
    }