Skip to main content

Defining HTTP Path Operations

When your FastAPI application grows, you can use APIRouter to group related path operations into separate files. This keeps your code modular and allows you to apply shared configurations like prefixes and dependencies to entire groups of routes at once.

from fastapi import APIRouter

router = APIRouter()

@router.get("/users/")
async def read_users():
return [{"username": "Rick"}, {"username": "Morty"}]

@router.post("/users/")
async def create_user(user: dict):
return {"message": "User created", "user": user}

Configuring Router-Level Settings

You can define settings like prefixes, tags, and dependencies once when instantiating the APIRouter. These settings automatically apply to every path operation defined within that router.

from fastapi import APIRouter, Depends
# from ..dependencies import get_token_header

router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(get_token_header)],
responses={404: {"description": "Not found"}},
)

@router.get("/") # This endpoint becomes /items/
async def read_items():
return [{"name": "Item 1"}]

@router.get("/{item_id}") # This endpoint becomes /items/{item_id}
async def read_item(item_id: str):
return {"item_id": item_id}

Including Routers in the Main App

Once you have defined your routes in an APIRouter, you must include it in your main FastAPI application using the include_router() method. This merges the router's paths into the application's global routing table.

from fastapi import FastAPI
from .routers import items, users

app = FastAPI()

app.include_router(users.router)
app.include_router(items.router)

Customizing Inclusion

You can provide additional configuration when calling include_router(). This is useful for adding a prefix or tags to a router that was defined generically in another module, allowing you to reuse the same router in different contexts.

# Adding a prefix and tags only at the point of inclusion
app.include_router(
admin.router,
prefix="/admin",
tags=["admin"],
)

Defining Multiple HTTP Methods

While decorators like .get(), .post(), and .put() are the standard way to define operations, you can use the .api_route() method to define a path operation that handles multiple HTTP methods with a single function.

@router.api_route("/items/{item_id}", methods=["GET", "POST"])
async def handle_item(item_id: str):
# This function handles both GET and POST requests to the same path
return {"item_id": item_id}

Troubleshooting: Prefix Formatting

FastAPI enforces strict formatting for path prefixes in the APIRouter constructor to ensure consistent URL generation.

  • A prefix must start with a forward slash /.
  • A prefix must NOT end with a forward slash /.

If these rules are violated, FastAPI raises an AssertionError during initialization:

# This will raise: AssertionError: A path prefix must start with '/'
router = APIRouter(prefix="items")

# This will raise: AssertionError: A path prefix must not end with '/'...
router = APIRouter(prefix="/items/")

Note that APIRouter is not "mounted" like a sub-application; its routes are merged directly into the parent. This means that dependencies and tags defined during include_router() are additive to those already defined on the APIRouter instance or the individual path operations.