Versioning Dependency¶
The versioning() factory is how an endpoint is marked as versioned. It returns a VersioningSupport instance suitable for Depends().
Marking is mandatory
An endpoint without this dependency does not participate in versioning: it is never inherited into newer versions and stays only where it is declared. This is a deliberate opt-in, not a default.
The until semantics¶
versioning(*, until: int | None = None) controls the range of versions an endpoint is available in:
| Value | Behaviour |
|---|---|
until=None (default) |
The endpoint is available from its own version onwards, in every later one |
until=N |
The endpoint is available from its own version through version N, inclusive |
Extra rules:
- If a route carries several
versioningdependencies (say, one on the router and one on the endpoint), the smallest declareduntilwins. - An
untilbelow the version that declares the endpoint is a contradiction: the library emits aUserWarning, the endpoint stays available in its own version but is inherited nowhere.
versioning() does not mean \"this version only\"
Called without arguments it means "available through the latest version", including versions mounted later. To limit an endpoint to a single version, pass an until equal to that version's number.
Ways to attach it¶
The dependency is accepted everywhere FastAPI accepts dependencies:
from fastapi import APIRouter, Depends, FastAPI
from fastapi_easy_versioning import versioning
v1_app = FastAPI(api_version=1)
# On an endpoint — through the decorator
@v1_app.get("/endpoint", dependencies=[Depends(versioning())])
def endpoint() -> None: ...
# Through add_api_route
v1_app.add_api_route("/added", endpoint, dependencies=[Depends(versioning(until=2))])
# On a whole router at once — every endpoint of it is versioned
router = APIRouter(dependencies=[Depends(versioning())])
@router.get("/router-endpoint")
def router_endpoint() -> None: ...
v1_app.include_router(router)
Reading the metadata inside an endpoint¶
The dependency can be injected into an endpoint — then it returns a VersionInfo named tuple with the route's resolved versioning configuration:
origin— the version that declared the endpoint;until— the last version the endpoint is available in. If nountilwas declared explicitly, this is the latest existing API version.
from typing import Annotated
from fastapi import Depends, FastAPI
from fastapi_easy_versioning import VersionInfo, versioning
v1_app = FastAPI(api_version=1)
@v1_app.get("/endpoint")
def endpoint(version: Annotated[VersionInfo, Depends(versioning())]) -> str:
return f"Available from version {version.origin} through version {version.until}"
Injection works in WebSocket endpoints too:
from typing import Annotated
from fastapi import Depends, FastAPI, WebSocket
from fastapi_easy_versioning import VersionInfo, versioning
v1_app = FastAPI(api_version=1)
@v1_app.websocket("/ws")
async def ws_endpoint(
websocket: WebSocket,
version: Annotated[VersionInfo, Depends(versioning())],
) -> None:
await websocket.accept()
await websocket.send_text(f"Available from version {version.origin}")
await websocket.close()
Diagnostics¶
If versioning has not been initialized, injecting VersionInfo fails with a RuntimeError listing the possible causes:
VersioningMiddlewareis not added to the application that mounts the versions;- the sub-application was not created with
FastAPI(api_version=<int>); - the route was registered after the first request and
rebuild_versioningwas never called.
Full reference
Signatures and detailed descriptions live in the API reference.