Module Router¶
ModuleRouter
allows you to define your route handlers as standalone functions, offering an alternative to using classes. This can be advantageous for Python developers who prefer using functions. Importantly, using ModuleRouter
does not restrict your access to other features provided by Ellar.
Usage¶
The Ellar CLI tool automatically generates a routers.py
file with every create-module
scaffold command. This file serves as a concise guide on utilizing the ModuleRouter
class.
Now, let's leverage the routers.py file generated in our prior project to implement two route functions, namely addition and subtraction.
# project_name/apps/car/routers.py
"""
Define endpoints routes in python function fashion
example:
my_router = ModuleRouter("/cats", tag="Cats", description="Cats Resource description")
@my_router.get('/')
def index(request: Request):
return {'detail': 'Welcome to Cats Resource'}
"""
from ellar.common import ModuleRouter
from ellar.openapi import ApiTags
math_router = ModuleRouter('/math')
open_api_tag = ApiTags(name='Math')
open_api_tag(math_router)
@math_router.get('/add')
def addition(a: int, b: int):
return a + b
@math_router.get('/subtract')
def subtraction(a: int, b: int):
return a - b
In the provided example, the math_router
is created with a prefix /math
and an OPENAPI tag 'Math'. Two routes, addition(a:int, b:int)
and subtraction(a:int, b:int)
, are added to the router, each handling two query parameters ('a' and 'b') of integer type. These functions perform the specified mathematical operations and return the results.
To make the math_router
visible to the application, it is registered with the current injector using current_injector.register(ModuleRouter, math_router)
. This step ensures that the router is recognized and accessible within the application.
Registering Module Router¶
Like controllers, ModuleRouters also need to be registered to their root module to be used in a web application. In the example provided above, the math_router
would be registered under the project_name/apps/car/module.py
file.
This registration process typically involves importing the math_router
and then adding it to the list of routers
in the module.py
file. This allows the router to be recognized by the application and its routes to be available to handle requests.
from ellar.common import Module
from ellar.core import ModuleBase
from ellar.di import Container
from .controllers import CarController
from .routers import math_router
@Module(
controllers=[CarController],
providers=[],
routers=[math_router],
)
class CarModule(ModuleBase):
pass
Accessing Other Request Object¶
In functional route handle, we can access request object and response object through custom decorators or type annotation as shown below.
By Type Annotation¶
Let's inject request and response object in addition
route handler function from our previous example
from ellar.core import Request
from ellar.common import ModuleRouter, Response
math_router = ModuleRouter('/math', name='Math')
@math_router.get('/add')
def addition(request: Request, res: Response, a:int, b:int):
res.headers['x-operation'] = 'Addition'
return dict(is_request_object=isinstance(request, Request), is_response_object=isinstance(res, Response), operation_result=a + b)
By Custom decorators¶
You can also achieve the same result by using custom decorator.
from ellar.core import Request
from ellar.common import ModuleRouter,Response, Inject
math_router = ModuleRouter('/math', name='Math')
@math_router.get('/add')
def addition(request:Inject[Request], res:Inject[Response], a:int, b:int):
res.headers['x-operation'] = 'Addition'
return dict(is_request_object=isinstance(request, Request), is_response_object=isinstance(res, Response), operation_result=a + b)
Inject Services¶
We can also inject service providers just like controller routes using the Provide
function.
from ellar.core import Config
from ellar.common import ModuleRouter, Response, Inject
math_router = ModuleRouter('/math', name='Math')
@math_router.get('/subtract')
def subtraction(a:int, b:int, res:Response, config:Inject[Config]):
res.headers['x-operation'] = 'Subtraction'
return dict(
is_config=isinstance(config, Config),
operation_result=a - b
)