Getting Started with APIRouter
As your FastAPI application grows, putting all your path operations in a single file becomes difficult to maintain. The APIRouter class allows you to organize your code into multiple files and logical groups, making it easier to manage large projects.
In this tutorial, you will build a modular application by splitting user and item management into separate modules.
Prerequisites
To follow this tutorial, you should have a basic FastAPI application structure. We will use a directory layout like this:
.
├── app
│ ├── main.py
│ └── routers
│ ├── items.py
│ └── users.py
1. Create a Router for Users
First, create a module for user-related path operations. Instead of using the FastAPI class, you use APIRouter from fastapi.routing.
In app/routers/users.py:
from fastapi import APIRouter
router = APIRouter()
@router.get("/users/", tags=["users"])
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]
@router.get("/users/me", tags=["users"])
async def read_user_me():
return {"username": "fakecurrentuser"}
The router object works just like the app object. You can use decorators like @router.get(), @router.post(), and others to define path operations.
2. Include the Router in your Main App
To make these routes available in your application, you must include the router in your main FastAPI instance using the include_router method.
In app/main.py:
from fastapi import FastAPI
from .routers import users
app = FastAPI()
app.include_router(users.router)
@app.get("/")
async def root():
return {"message": "Hello World"}
When you run your application, the routes defined in users.py (like /users/) will be automatically registered to the main app.
3. Simplify Routes with Prefixes and Tags
You can avoid repeating the same path prefix (like /users) and tags for every operation by configuring them directly in the APIRouter constructor.
In app/routers/items.py:
from fastapi import APIRouter, HTTPException
router = APIRouter(
prefix="/items",
tags=["items"],
responses={404: {"description": "Not found"}},
)
fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}}
@router.get("/")
async def read_items():
return fake_items_db
@router.get("/{item_id}")
async def read_item(item_id: str):
if item_id not in fake_items_db:
raise HTTPException(status_code=404, detail="Item not found")
return {"name": fake_items_db[item_id]["name"], "item_id": item_id}
By setting prefix="/items", the @router.get("/") decorator actually creates the path /items/. Note that FastAPI enforces specific rules for prefixes:
- They must start with a forward slash
/. - They must NOT end with a forward slash
/.
4. Apply Dependencies to All Routes
If you have logic that should run for every route in a group—such as checking an API token—you can add dependencies to the router.
from fastapi import APIRouter, Depends
from ..dependencies import get_token_header
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
)
Any dependency added here will be executed for every path operation defined within this router.
5. Nesting Routers
FastAPI also allows you to include a router inside another router. This is useful for deeply nested API structures.
from fastapi import APIRouter
parent_router = APIRouter(prefix="/api/v1")
child_router = APIRouter(prefix="/users")
@child_router.get("/")
async def get_users():
return {"message": "List of users"}
# This makes the route available at /api/v1/users/
parent_router.include_router(child_router)
Summary of Configuration Options
When initializing APIRouter or using include_router, you can use several parameters to control the behavior of the grouped routes:
prefix: A string added to the beginning of all paths in the router.tags: A list of strings used to group operations in the generated OpenAPI documentation (Swagger UI).dependencies: A list ofDepends()objects applied to all operations.responses: A dictionary of additional responses (like 404 or 403) that apply to all operations.strict_content_type: WhenTrue(default), FastAPI ensures requests with a body include aContent-Typeheader before parsing JSON, which helps protect against certain CSRF vulnerabilities.
By using APIRouter, you have successfully transformed a single-file script into a modular, scalable FastAPI application.