diff options
| author | 2020-10-25 19:50:36 +0000 | |
|---|---|---|
| committer | 2020-10-25 19:50:36 +0000 | |
| commit | a68686f9d77147fb034d6dea646b3fb9336faf2e (patch) | |
| tree | bf4f04868840a54c1c853bf961e5eae9db428f23 /backend | |
| parent | Add database middleware (diff) | |
Add route class and route manager for dynamic route loading
Diffstat (limited to '')
| -rw-r--r-- | backend/route.py | 17 | ||||
| -rw-r--r-- | backend/route_manager.py | 57 | 
2 files changed, 74 insertions, 0 deletions
| diff --git a/backend/route.py b/backend/route.py new file mode 100644 index 0000000..af68b93 --- /dev/null +++ b/backend/route.py @@ -0,0 +1,17 @@ +""" +Base class for implementing dynamic routing. +""" +from starlette.endpoints import HTTPEndpoint + + +class Route(HTTPEndpoint): +    name: str = None +    path: str = None + +    @classmethod +    def check_parameters(cls): +        if cls.name is None: +            raise ValueError(f"Route {cls.__name__} has not defined a name") + +        if cls.path is None: +            raise ValueError(f"Route {cls.__name__} has not defined a path") diff --git a/backend/route_manager.py b/backend/route_manager.py new file mode 100644 index 0000000..ef5d835 --- /dev/null +++ b/backend/route_manager.py @@ -0,0 +1,57 @@ +""" +Module to dynamically generate a Starlette routing map based on a directory tree. +""" + +import importlib +import inspect +from pathlib import Path + +from starlette.routing import Route as StarletteRoute, Mount +from nested_dict import nested_dict + +from backend.route import Route + + +def construct_route_map_from_dict(route_dict: dict): +    route_map = [] +    for mount, item in route_dict.items(): +        if inspect.isclass(item): +            route_map.append(StarletteRoute(mount, item)) +        else: +            route_map.append(Mount(mount, routes=construct_route_map_from_dict(item))) + +    return route_map + + +def create_route_map(): +    routes_directory = Path("backend") / "routes" + +    route_dict = nested_dict() + +    for file in routes_directory.rglob("*.py"): +        import_name = f"{str(file.parent).replace('/', '.')}.{file.stem}" + +        route = importlib.import_module(import_name) + +        for _member_name, member in inspect.getmembers(route): +            if inspect.isclass(member): +                if issubclass(member, Route) and member != Route: +                    member.check_parameters() + +                    levels = str(file.parent).split("/")[2:] + +                    current_level = None +                    for level in levels: +                        if current_level is None: +                            current_level = route_dict[f"/{level}"] +                        else: +                            current_level = current_level[f"/{level}"] + +                    if current_level is not None: +                        current_level[member.path] = member +                    else: +                        route_dict[member.path] = member + +    route_map = construct_route_map_from_dict(route_dict.to_dict()) + +    return route_map | 
