If the same function name is defined under multiple APIRouters, request.url_for
and router.url_path_for
would return the first matching function name (in the order of include_router).
Here is a way to get the correct url with the tag of APIRouter when there is a function name conflict, if someone needs it:
Step 1: put this in your __init__.py
:
def url_of(request: Request, name: str, **path_params: dict):
from fastapi.routing import APIRoute
from starlette.routing import NoMatchFound
tag, tid, fname = None, name.find('.'), name
if tid > 0:
tag = name[:tid]
fname = name[tid + 1:]
url_no_tag = None
for route in request.app.router.routes:
if not isinstance(route, APIRoute):
continue
if fname == route.name and (not tag or tag in route.tags):
try:
url_path = route.url_path_for(fname, **path_params)
url_no_tag = url_path.make_absolute_url(base_url=request.base_url)
if tag:
return url_no_tag
except NoMatchFound:
pass
if url_no_tag:
return url_no_tag
return request.url_for(name, **path_params)
Step 2: add a tag for APIRouters:
router = APIRouter(prefix='/user', tags=['user'])
@router.get('/')
def login():
return 'login page'
Step 3: retrieve the url in any where:
@router2.get('/test')
def test(request: Request):
return RedirectResponse(url_of(request, 'user.login') + '?a=1')
2021/07/10 rename url_as
to url_of