FastAPI: how to access the APIRoute object inside the dependency

9.3k views Asked by At

I'm using FastAPI where the main app is using include_router to add extra routes to the fastAPI app.

I would like to add a generic validation on all the routes. I found in the documentation that you can achieve this by using the dependencies when including a router.

https://fastapi.tiangolo.com/tutorial/bigger-applications/#the-main-fastapi

This works and is getting executed by all the http requests. Thus far everything great!

Now, I want to know inside this generic validation function (being injected using the Depends() in all the routes) what route is invoking the function.

I found a way to get access to the actual request (using fastapi.routing.Request as input parameter for the function) but I would like to get access to the function or the name of the APIRoute itself.

from fastapi import FastAPI, Depends
from fastapi.routing import Request, APIRoute

async def check_permission(req: Request, route: APIRoute):
    print("test me")

app = FastAPI()
app.include_router(admin.service_api, dependencies=[Depends(check_permission)])

RuntimeError: no validator found for <class 'fastapi.routing.APIRoute'>

Perhaps this is a bad idea all together and should I do it in a different way? All suggestions are very much appreciated. Thank you.

3

There are 3 answers

3
Yagiz Degirmenci On

Actually using the Request object is the best practice, since it holds the entire data of the Request, I can not see a reason to not to use it.

Even if you create a workaround for this error, you can not get this work in a proper way. Because the APIRoute is not a valid Pydantic Field type, so our FastAPI should be raising FastAPIError for this.

So the answer is: You should use Request object.

0
CodingEdge On

I think I found a workaround (by using the Request object). Maybe it's not very Pythonic:

async def check_permission(req: Request):
   f = req.scope['endpoint'] 
   # f is the function object of the fast api route endpoint
0
Alex On

I hope this helps, it returns APIRoute object, can be used inside the dependency. I'm not sure it is the safe way of doing this. Request object should be injected beforehand.

api_route = next(item for item in request.app.routes if isinstance(item, APIRoute) and item.dependant.cache_key[0] == request.scope['endpoint'])