| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
English · Русский
Versioned APIs for FastAPI — one sub-application per version, automatic inheritance of endpoints from older versions into newer ones, and an up-to-date OpenAPI schema for every version.
Once an API lives in several versions, routes have to be copied between them by hand: /v2 must serve everything /v1 served, minus what was deliberately dropped. The copies drift apart, /v1/docs and /v2/docs start lying, and "which versions is this endpoint even in?" becomes a question for git blame. This package makes the availability range a property of the endpoint: declare it once, mark it with a dependency, and it shows up in every later version by itself.
app = FastAPI()
app.add_middleware(VersioningMiddleware)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
@app_v1.get("/items", dependencies=[Depends(versioning())])
def items() -> list[Item]:
return get_items()Declared once in v1 — served at /v1/items and /v2/items, and present in both versions' Swagger. No duplicated route, no hand-maintained schema.
pip install fastapi-easy-versioningRequires Python 3.10+ and FastAPI ≥ 0.95 (0.137.0 and 0.137.1 are excluded). fastapi is the only runtime dependency.
Versioning is built from two pieces that work only together.
1. Mount one sub-application per version and add the middleware. The middleware goes on the aggregating application — the one that directly mounts the versions, never on the versions themselves.
from fastapi import Depends, FastAPI
from fastapi_easy_versioning import VersioningMiddleware, versioning
app = FastAPI()
app_v1 = FastAPI(api_version=1) # the version number is an int; 0 is valid
app_v2 = FastAPI(api_version=2)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
app.add_middleware(VersioningMiddleware)2. Mark the endpoints. Marking is opt-in: an endpoint without the dependency stays in its own version only.
@app_v1.get("/only-v1", dependencies=[Depends(versioning(until=1))])
def only_v1() -> str:
return "Available only in version v1"
@app_v1.get("/all-versions", dependencies=[Depends(versioning())])
def all_versions() -> str:
return "Available in all versions starting from v1"
@app_v2.get("/from-v2", dependencies=[Depends(versioning())])
def from_v2() -> str:
return "Available starting from v2 and in all future versions"versioning() without until means "through the latest version", not "in this one only" — a common source of surprise. The dependency is accepted anywhere FastAPI accepts one, including APIRouter(dependencies=[...]) to version a whole router at once.
3. Read the version metadata where you need it. Injected into the signature, the same dependency yields the resolved range:
@app_v1.get("/where-am-i")
def where_am_i(version: Annotated[VersionInfo, Depends(versioning())]) -> str:
return f"Available from v{version.origin} through v{version.until}"The result: /v1/only-v1 responds while /v2/only-v1 is a 404; /all-versions responds in both; /v2/from-v2 responds while /v1/from-v2 is a 404 — and each version's /docs shows exactly what that version serves.
📖 Full documentation — quickstart, the guide (dependency, middleware, recipes, limitations), runnable examples and an auto-generated API reference. Available in English and Russian.
MIT.
| Back | FazBrowse Home | New Git URL |