Skip to content

Commit

Permalink
refactor: openApi made lazy.
Browse files Browse the repository at this point in the history
All add_route methods have auth_required, openapi_name and openapi_tags which get stored in the route.
Instead of incrementally adding them to openapi routes they are added all at once in app.start
include_routes now additionally tracks the list of routers whose routes have been added to the main app. This will be used more later to avoid merging routes until app.start for more flexibility
  • Loading branch information
dave42w committed Dec 2, 2024
1 parent 0dccef3 commit 642eac9
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 40 deletions.
61 changes: 24 additions & 37 deletions robyn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def __init__(
self.event_handlers: dict = {}
self.exception_handler: Optional[Callable] = None
self.authentication_handler: Optional[AuthenticationHandler] = None
self.included_routers: List[Router] = []

def init_openapi(self) -> None:
if self.config.disable_openapi:
Expand Down Expand Up @@ -113,6 +114,8 @@ def add_route(
handler: Callable,
is_const: bool = False,
auth_required: bool = False,
openapi_name: str = "",
openapi_tags: Union[List[str], None] = None,
):
"""
Connect a URI to a handler
Expand All @@ -128,6 +131,10 @@ def add_route(
"""
injected_dependencies = self.dependencies.get_dependency_map(self)

list_openapi_tags: List[str] = []
if not self.config.disable_openapi and openapi_tags is not None:
list_openapi_tags = openapi_tags

if auth_required:
self.middleware_router.add_auth_middleware(endpoint)(handler)

Expand All @@ -148,6 +155,9 @@ def add_route(
endpoint=endpoint,
handler=handler,
is_const=is_const,
auth_required=auth_required,
openapi_name=openapi_name,
openapi_tags=list_openapi_tags,
exception_handler=self.exception_handler,
injected_dependencies=injected_dependencies,
)
Expand Down Expand Up @@ -258,6 +268,8 @@ def _add_openapi_routes(self, auth_required: bool = False):
logger.error("No openAPI")
return

self.router.prepare_routes_openapi(self.openapi, self.included_routers)

self.add_route(
route_type=HttpMethod.GET,
endpoint="/openapi.json",
Expand Down Expand Up @@ -387,10 +399,7 @@ def get(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("get", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.GET, endpoint, handler, const, auth_required)
return self.add_route(HttpMethod.GET, endpoint, handler, const, auth_required, openapi_name, openapi_tags)

return inner

Expand All @@ -411,10 +420,7 @@ def post(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("post", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.POST, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.POST, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -435,10 +441,7 @@ def put(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("put", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.PUT, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.PUT, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -459,10 +462,7 @@ def delete(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("delete", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.DELETE, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.DELETE, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -483,10 +483,7 @@ def patch(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("patch", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.PATCH, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.PATCH, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -507,10 +504,7 @@ def head(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("head", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.HEAD, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.HEAD, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -531,10 +525,7 @@ def options(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("options", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.OPTIONS, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.OPTIONS, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -555,10 +546,7 @@ def connect(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("connect", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.CONNECT, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.CONNECT, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -579,10 +567,7 @@ def trace(
"""

def inner(handler):
if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_openapi_path_obj("trace", endpoint, openapi_name, openapi_tags, handler)

return self.add_route(HttpMethod.TRACE, endpoint, handler, auth_required=auth_required)
return self.add_route(HttpMethod.TRACE, endpoint, handler, auth_required=auth_required, openapi_name=openapi_name, openapi_tags=openapi_tags)

return inner

Expand All @@ -592,12 +577,14 @@ def include_router(self, router):
:param router Robyn: the router object to include the routes from
"""
self.included_routers.append(router)

self.router.routes.extend(router.router.routes)
self.middleware_router.global_middlewares.extend(router.middleware_router.global_middlewares)
self.middleware_router.route_middlewares.extend(router.middleware_router.route_middlewares)

if not self.config.disable_openapi and self.openapi is not None:
self.openapi.add_subrouter_paths(router.openapi)
self.openapi.add_subrouter_paths(self.openapi)

# extend the websocket routes
prefix = router.prefix
Expand Down
2 changes: 1 addition & 1 deletion robyn/processpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def spawn_process(
server.set_response_headers_exclude_paths(excluded_response_headers_paths)

for route in routes:
route_type, endpoint, function, is_const = route
route_type, endpoint, function, is_const, auth_required, openapi_name, openapi_tags = route
server.add_route(route_type, endpoint, function, is_const)

for middleware_type, middleware_function in global_middlewares:
Expand Down
24 changes: 22 additions & 2 deletions robyn/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from robyn.authentication import AuthenticationHandler, AuthenticationNotConfiguredError
from robyn.dependency_injection import DependencyMap
from robyn.jsonify import jsonify
from robyn.openapi import OpenAPI
from robyn.responses import FileResponse
from robyn.robyn import FunctionInfo, Headers, HttpMethod, Identity, MiddlewareType, QueryParams, Request, Response, Url
from robyn.types import Body, Files, FormData, IPAddress, Method, PathParams
Expand All @@ -19,11 +20,18 @@
_logger = logging.getLogger(__name__)


def lower_http_method(method: HttpMethod):
return str(method).lower()[11:]


class Route(NamedTuple):
route_type: HttpMethod
route: str
function: FunctionInfo
is_const: bool
auth_required: bool
openapi_name: str
openapi_tags: List[str]


class RouteMiddleware(NamedTuple):
Expand Down Expand Up @@ -108,6 +116,9 @@ def add_route( # type: ignore
endpoint: str,
handler: Callable,
is_const: bool,
auth_required: bool,
openapi_name: str,
openapi_tags: List[str],
exception_handler: Optional[Callable],
injected_dependencies: dict,
) -> Union[Callable, CoroutineType]:
Expand Down Expand Up @@ -226,7 +237,7 @@ def inner_handler(*args, **kwargs):
params,
new_injected_dependencies,
)
self.routes.append(Route(route_type, endpoint, function, is_const))
self.routes.append(Route(route_type, endpoint, function, is_const, auth_required, openapi_name, openapi_tags))
return async_inner_handler
else:
function = FunctionInfo(
Expand All @@ -236,9 +247,18 @@ def inner_handler(*args, **kwargs):
params,
new_injected_dependencies,
)
self.routes.append(Route(route_type, endpoint, function, is_const))
self.routes.append(Route(route_type, endpoint, function, is_const, auth_required, openapi_name, openapi_tags))
return inner_handler

def prepare_routes_openapi(self, openapi: OpenAPI, included_routers: List) -> None:
for route in self.routes:
openapi.add_openapi_path_obj(lower_http_method(route.route_type), route.route, route.openapi_name, route.openapi_tags, route.function.handler)

# TODO! after include_routes does not immediatelly merge all the routes
# for router in included_routers:
# for route in router:
# openapi.add_openapi_path_obj(lower_http_method(route.route_type), route.route, route.openapi_name, route.openapi_tags, route.function.handler)

def get_routes(self) -> List[Route]:
return self.routes

Expand Down

0 comments on commit 642eac9

Please sign in to comment.