Lift the `fastapi <0.137` cap once route introspection handles `_IncludedRouter` (fastapi ≥ 0.137)
What is the technical debt you think should be addressed?
We currently pin fastapi>=0.115.0,<0.137 in pyproject.toml (resolves to 0.136.3; added while unblocking dependabot PR #6587). That cap is a workaround for a fastapi ≥ 0.137 behavior change, not a real compatibility constraint.
Mechanism: in fastapi ≥ 0.137, APIRouter.include_router() no longer flattens the included router's APIRoutes into the parent's router.routes. Instead it appends a single _IncludedRouter(BaseRoute) wrapper (defined in fastapi/routing.py; constructed at the end of include_router), and the sub-routes are reachable only via .original_router.routes. Verified boundary: 0.136.3 works; 0.140.13 and 0.141.1 both change behavior.
This breaks any code or test that walks router.routes expecting flat APIRoute objects with .path / .methods / .endpoint:
- Unit tests (verified):
tests/unit/core/routers/test_connectors_router.py— 11 of 15 tests fail. The_get_endpointhelper (line 58) readsrouter.routesoff the admin router, the only router built with internalinclude_routernesting (src/ogx_api/admin/fastapi_routes.py:203-204). The 4 OpenAPI-schema tests still pass (schema generation still resolves nested routes). - Server / library-client route introspection (product gap):
get_router_routes(src/ogx/core/server/fastapi_router_registry.py:98-100) filtersisinstance(route, APIRoute)with no recursion, so it drops the admin router's nested routes. It feedsinitialize_route_impls(src/ogx/core/server/routes.py:60, used by the library client atlibrary_client.py:731) and the/admin/inspect/routes+ admin route listing (inspect.py:91,admin.py:215). By contrast the server auth path already handles this —build_route_impls_from_routes→_collect_api_routes(routes.py:108-119) recurses into.original_routerwith an explicit "FastAPI >= 0.137" comment — but that adaptation is inconsistent, leavingget_router_routesandmetrics.py:94unhandled.
Because the cap is a hard ceiling, it will keep blocking every future fastapi dependabot bump until the route-introspection code (and the test) are made nesting-aware.
What is the benefit of addressing this technical debt?
- Restores the ability to track the latest
fastapiwithout a version ceiling, so dependabot python-deps PRs stop needing manual reverts. - Makes server / library-client route introspection correct for current and future fastapi (fixes the latent admin-API route drop in
get_router_routes). - Removes a "magic" version cap that isn't self-explanatory without this issue for context.
Other thoughts
- The root fix belongs in the route-introspection helpers, not the dependency pin. Make every
.routesconsumer nesting-aware:- Reimplement
get_router_routeson top of the existing recursive_collect_api_routes(or share one helper) soinitialize_route_impls,inspect.py, andadmin.pyall see nested routes. - Check
metrics.py:94(for route in router.routes) for the same flat-router assumption. - Make
test_connectors_router.py::_get_endpointrobust to fastapi's router nesting (flatten viaoriginal_router, or match on resolved paths) so it doesn't couple to fastapi's internalrouter.routesshape.
- Reimplement
- Once all
.routesconsumers + the test are verified against fastapi ≥ 0.137, remove the cap in a single PR. - Possibly a
good first issueonce the intended route-collection behavior is documented.
Source: ogx-ai/ogx