Modular Routing with include_router
To organize a large application into multiple files and apply shared configurations like path prefixes, tags, and dependencies to entire groups of routes, use the APIRouter class and the include_router method.
Basic Modular Routing
Define your routes in a separate module using APIRouter, then include that router in your main FastAPI application.
File: routers/items.py
from fastapi import APIRouter, Depends, HTTPException
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)
@router.get("/")
async def read_items():
return {"item": "portal gun"}
@router.get("/{item_id}")
async def read_item(item_id: str):
return {"item_id": item_id}
File: main.py
from fastapi import FastAPI
from .routers import items
app = FastAPI()
# Include the router from the items module
app.include_router(items.router)
Applying Configurations at Inclusion
You can apply or override configurations when calling include_router. This is useful for reusing the same router with different prefixes or security requirements.
from fastapi import Depends, FastAPI
from .internal import admin
from .dependencies import get_token_header
app = FastAPI()
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
dependencies=[Depends(get_token_header)],
responses={418: {"description": "I'm a teapot"}},
)
Key Configuration Parameters
The APIRouter and include_router method support several parameters that affect all contained path operations:
prefix: A string that will be prepended to all paths in the router. It must start with/and must not end with/.tags: A list of strings or Enums used for grouping routes in the OpenAPI documentation. These are additive; if a route has its own tags, they are combined with the router's tags.dependencies: A sequence ofDepends()objects that will be executed for every request to routes within this router.responses: A dictionary of additional responses (e.g.,{404: {"description": "Not found"}}) that will be included in the OpenAPI schema for all routes.
Nesting Routers
Routers can be included within other routers to create a hierarchical structure before finally being included in the main FastAPI app.
from fastapi import APIRouter, FastAPI
app = FastAPI()
parent_router = APIRouter(prefix="/parent")
child_router = APIRouter(prefix="/child")
@child_router.get("/item")
async def get_item():
return {"message": "Found in /parent/child/item"}
# Nest the child router into the parent
parent_router.include_router(child_router)
# Include the parent into the main app
app.include_router(parent_router)
Troubleshooting and Constraints
- Prefix Formatting: The
APIRouterenforces strict prefix formatting. If your prefix does not start with/or ends with/, the application will raise anAssertionErrorduring initialization. - Circular Inclusion: You cannot include a router instance into itself. The
include_routermethod contains an assertionassert self is not routerto prevent infinite recursion. - Empty Paths: If you include a router without a
prefix, the routes inside that router cannot have empty paths (e.g.,@router.get("")). This will raise aFastAPIError. - Additive Metadata: Tags and dependencies are cumulative. If you define dependencies at the
FastAPIapp level, theinclude_routerlevel, and the individual route level, all of them will be executed in that order.