Behavior of `include_router` method
See original GitHub issueHi, I would like to prepare a tool responsible for logging the requests & responses. I have found out, that
the best way to do it is to prepare a custom APIRoute
class. My case is that I have got one main APIRouter
to which I’m pinning a lot of smaller ones, in the code, it looks like:
router_1 = APIRouter()
router_2 = APIRouter()
router_3 = APIRouter()
api_router = APIRouter(route_class=MyLoggingClass)
api_router.include_router(router_1)
api_router.include_router(router_2)
api_router.include_router(router_3)
The problem is that the pinned small routers are not overwriting their own route_class
from the main one, because of what
MyLoggingClass
has never been called and I can’t capture my logs.
When I am calling api_router.routes
all objects are still APIRoute
instances instead of MyLoggingClass
.
Is it a proper behavior of the include_router
method? Shouldn’t it interfere with the object which is being added and
change his route_class to the one to which is he being added?
If yes, do you folks know any way how to achieve my goal without any workarounds?
Thanks in advance for your comments & help! 😃
EDIT: Added full copy & paste code snippet which describes the whole situation include actual output and expected output inside docstring:
from typing import Callable
from fastapi import APIRouter, FastAPI, Request, Response
from fastapi.routing import APIRoute
class TestRoute(APIRoute):
def get_route_handler(self) -> Callable:
original_route_handler = super().get_route_handler()
async def custom_route_handler(request: Request) -> Response:
response = await original_route_handler(request)
print("Example print... -.^")
return response
return custom_route_handler
app = FastAPI()
api_router = APIRouter(route_class=TestRoute)
router_1 = APIRouter()
router_2 = APIRouter()
router_3 = APIRouter(route_class=TestRoute)
@router_1.get("/router_1")
async def r_1():
return {"I am router": 1}
@router_2.get("/router_2")
async def r_2():
return {"I am router": 2}
@router_3.get("/router_3")
async def r_3():
return {"I am router": 3}
api_router.include_router(router_1)
api_router.include_router(router_2)
api_router.include_router(router_3)
@app.get("/")
async def api_r():
return {"Routes": str(api_router.routes)}
app.include_router(api_router)
"""
Actual output:
{
"Routes":"
[
<fastapi.routing.APIRoute object at 0x7fa1d7dd8e50>,
<fastapi.routing.APIRoute object at 0x7fa1d7de41f0>,
<fastapi.routing.TestRoute object at 0x7fa1d7de4f70>,
]"
}
Expected output:
{
"Routes":"
[
<fastapi.routing.TestRoute object at 0x7fa1d7dd8e50>,
<fastapi.routing.TestRoute object at 0x7fa1d7de41f0>,
<fastapi.routing.TestRoute object at 0x7fa1d7de4f70>,
]"
}
"""
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:5
@aalifadv thanks for the answer!
My first thought and implementation were Middleware, but then I hit the wall while I was trying to get the request and response body.
According to the topics I found it is impossible to fetch the request body via
Middleware
- it’s coming from Starlette implementation as I understand.https://github.com/tiangolo/fastapi/issues/394 https://github.com/tiangolo/fastapi/issues/1123
I can pin the logger to each view and at the begging create a log from request and at the end from response or prepare Dependency pinned to the router which will create a log from request and in the middleware log the response, but my goal is to prepare one functionality which will make both that is why I put my eyes into
APIRoute
which according to the comments inside above topics, should be helpful 😃same issue with me does any one have a workaround