This is an issue when you include an APIRouter in a FastAPI application before adding child routers to it. The child router’s path operations will not be registered with the application.
FastAPI registers path operations at the moment you call include_router(). When you include a parent router in your FastAPI app, it
captures only the path operations that exist in that router at that specific moment.
If you later add a child router to the parent router using router.include_router(child_router), those new path operations are added to
the parent router object. However, the FastAPI app has already completed its registration process and won’t automatically pick up these new
routes.
This creates a situation where:
The issue is particularly subtle because no error or warning is raised. The code runs without complaints, but the endpoints simply don’t work. This can lead to confusion during development and testing, as the routes appear to be properly defined in the code but are mysteriously unavailable at runtime.
When child router endpoints are not properly registered:
This can cause significant debugging time as the code structure appears correct, but the runtime behavior doesn’t match expectations. In production, this could mean critical API functionality is unavailable to users.
Include all child routers in their parent routers before including the parent router in the FastAPI application. This ensures all path operations are registered when the parent router is added to the app.
from fastapi import FastAPI, APIRouter
app = FastAPI()
parent_router = APIRouter()
child_router = APIRouter()
@child_router.get("/items")
def get_items():
return {"items": []}
app.include_router(parent_router, prefix="/api")
parent_router.include_router(child_router) # Noncompliant
from fastapi import FastAPI, APIRouter
app = FastAPI()
parent_router = APIRouter()
child_router = APIRouter()
@child_router.get("/items")
def get_items():
return {"items": []}
parent_router.include_router(child_router)
app.include_router(parent_router, prefix="/api")
When organizing routers across multiple files, ensure the module-level includes happen in the correct order. Import and include child routers before including the parent router in the main application.
# main.py from fastapi import FastAPI from .routers import parent, child app = FastAPI() app.include_router(parent.router) parent.router.include_router(child.router) # Noncompliant
# main.py from fastapi import FastAPI from .routers import parent, child app = FastAPI() parent.router.include_router(child.router) app.include_router(parent.router)
For complex applications with multiple levels of nesting, build the router hierarchy from the bottom up. Include the deepest child routers first, then work your way up to the top-level routers.
from fastapi import FastAPI, APIRouter app = FastAPI() api_router = APIRouter() v1_router = APIRouter() users_router = APIRouter() app.include_router(api_router) api_router.include_router(v1_router, prefix="/v1") # Noncompliant v1_router.include_router(users_router, prefix="/users") # Noncompliant
from fastapi import FastAPI, APIRouter app = FastAPI() api_router = APIRouter() v1_router = APIRouter() users_router = APIRouter() v1_router.include_router(users_router, prefix="/users") api_router.include_router(v1_router, prefix="/v1") app.include_router(api_router)