Зависимость для версионирования¶
Фабрика versioning() — способ пометить эндпоинт как версионированный. Она возвращает экземпляр VersioningSupport, пригодный для использования в Depends().
Пометка обязательна
Эндпоинт без этой зависимости в версионировании не участвует: он не наследуется в новые версии и остаётся только там, где объявлен. Это осознанный opt-in, а не умолчание.
Семантика until¶
versioning(*, until: int | None = None) управляет диапазоном версий, в которых доступен эндпоинт:
| Значение | Поведение |
|---|---|
until=None (по умолчанию) |
Эндпоинт доступен со своей версии и во всех последующих |
until=N |
Эндпоинт доступен со своей версии по версию N включительно |
Дополнительные правила:
- Если у роута несколько
versioning-зависимостей (например, одна на роутере и одна на эндпоинте), действует минимальный из указанныхuntil. untilменьше версии, в которой объявлен эндпоинт, — противоречие: библиотека выдастUserWarning, эндпоинт останется доступен в своей версии, но не будет унаследован никуда.
versioning() — это не «только эта версия»
Вызов без аргументов означает «доступен вплоть до последней версии», включая версии, смонтированные позже. Чтобы ограничить эндпоинт одной версией, укажите until, равный её номеру.
Способы подключения¶
Зависимость принимается везде, где FastAPI принимает зависимости:
from fastapi import APIRouter, Depends, FastAPI
from fastapi_easy_versioning import versioning
v1_app = FastAPI(api_version=1)
# На эндпоинте — через декоратор
@v1_app.get("/endpoint", dependencies=[Depends(versioning())])
def endpoint() -> None: ...
# Через add_api_route
v1_app.add_api_route("/added", endpoint, dependencies=[Depends(versioning(until=2))])
# Сразу на весь роутер — версионируются все его эндпоинты
router = APIRouter(dependencies=[Depends(versioning())])
@router.get("/router-endpoint")
def router_endpoint() -> None: ...
v1_app.include_router(router)
Чтение метаданных в эндпоинте¶
Зависимость можно внедрить в эндпоинт — тогда она возвращает именованный кортеж VersionInfo с разрешённой конфигурацией версионирования роута:
origin— версия, в которой эндпоинт объявлен;until— последняя версия, в которой эндпоинт доступен. Еслиuntilне задавался явно, это последняя существующая версия API.
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"Доступен с версии {version.origin} до версии {version.until}"
Инъекция работает и в WebSocket-эндпоинтах:
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"Доступен с версии {version.origin}")
await websocket.close()
Диагностика¶
Если версионирование не инициализировано, попытка внедрить VersionInfo завершится RuntimeError с перечислением возможных причин:
VersioningMiddlewareне добавлен в приложение, монтирующее версии;- у субприложения не задан
FastAPI(api_version=<int>); - роут зарегистрирован после первого запроса, а
rebuild_versioningне вызывался.
Полный справочник
Сигнатуры и подробное описание — в справочнике API.