FastAPI Router Variants¶
Declare a route once and get path variants, API versioning and per-version OpenAPI documentation for FastAPI — for free.
fastapi-router-variants wraps APIRouter with a RouterWrapper that expands a
single route declaration into every variant it should serve: multiple paths,
multiple version prefixes (/v1/..., /v2/...), multiple mount prefixes, with
deprecation handled automatically. It then builds a separate OpenAPI schema per
version and mounts Swagger UI / ReDoc / openapi.json for each of them.
Requirements¶
- Python ≥ 3.12
- FastAPI ≥ 0.115
Install¶
Install with pip:
Or add it to your project with uv:
Quick start¶
from fastapi import FastAPI
from fastapi_router_variants import RouterDefaults, RouterWrapper
class ApiDefaults(RouterDefaults):
prefix = "/api" # mount every route under /api
version = True # force versioning on every route
version_range = (1, 3) # generate v1, v2, v3
version_default = 3 # the version served on unversioned doc URLs
RouterWrapper.defaults = ApiDefaults()
router = RouterWrapper()
@router.get("/users/{user_id}")
def get_user(user_id: int) -> dict[str, int]:
return {"id": user_id}
app = FastAPI()
app.include_router(router.base)
The single get declaration above registers:
RouterWrapper mirrors the APIRouter decorator surface — get, post,
put, patch, delete, api_route and websocket — while adding the
variant-expansion parameters (version, prefix, deployment, public, …).
The underlying APIRouter is available as router.base and is what you pass to
app.include_router(...).
On FastAPI >= 0.139 each include_router call leaves an opaque lazily-mounted
router in the app's routing table; under load Starlette makes those wrappers
retain the effective route tree, inflating memory. Once composition is done,
call flatten_included_routers(app) to splice the real routes back into place
and avoid the regression (a no-op on older FastAPI):
from fastapi_router_variants import flatten_included_routers
app = FastAPI()
app.include_router(router.base)
flatten_included_routers(app)
Flattened HTTP and WebSocket routes remain bound to app, so dependency
overrides configured through app.dependency_overrides continue to apply.
Where to go next¶
- Path variants — declare one route as several paths and flavors.
- API versioning — expand a route across a range of versions.
- Routing specs — composable predicates to classify routes.
- OpenAPI documentation — one documented API per version and category.
- API reference — every public symbol, with signatures.
License¶
fastapi-router-variants is licensed under the
MIT license.