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