Рецепты¶
Готовые приёмы для типовых задач.
Версионировать целый роутер¶
Зависимость, повешенная на APIRouter, распространяется на все его эндпоинты — помечать каждый по отдельности не нужно.
from fastapi import APIRouter, Depends, FastAPI
from fastapi_easy_versioning import versioning
users = APIRouter(prefix="/users", tags=["users"], dependencies=[Depends(versioning())])
@users.get("")
def list_users() -> list[User]: ...
@users.get("/{user_id}")
def get_user(user_id: int) -> User: ...
app_v1.include_router(users)
Один и тот же роутер можно включить в несколько версий — версией объявления для каждого набора роутов станет то приложение, в которое он включён.
Ограничить весь роутер
APIRouter(dependencies=[Depends(versioning(until=2))]) ограничивает разом все эндпоинты роутера. Если на конкретном эндпоинте указан свой until, сработает минимальный из двух.
Исключить эндпоинт из версионирования¶
Обратная задача решается отсутствием пометки: служебные и внутренние ручки просто не получают versioning().
- Останется только в v1. Ни в одну другую версию не попадёт и в их схемах не появится.
Заменить эндпоинт в новой версии¶
Достаточно объявить в новой версии свой эндпоинт с тем же путём: наследование в неё пропускается, а старая реализация продолжает работать в старых версиях.
@app_v1.get("/profile", dependencies=[Depends(versioning())])
def profile_v1() -> ProfileV1: ...
@app_v3.get("/profile", dependencies=[Depends(versioning())]) # (1)!
def profile_v3() -> ProfileV3: ...
- v1 и v2 отдают старый формат, v3 и все последующие — новый. В
/v3/docsпопадёт только новая схема ответа.
Добавить версию во время работы приложения¶
Наследование строится один раз, поэтому смонтированная позже версия требует явной пересборки.
from fastapi_easy_versioning import rebuild_versioning
app_v3 = FastAPI(api_version=3)
app.mount("/v3", app_v3)
rebuild_versioning(app) # (1)!
- Вызов идемпотентен: он не создаёт дублей для уже унаследованных роутов, зато пересчитывает
untilпо умолчанию — теперь «до последней версии» означает v3.
То же самое нужно после include_router или add_api_route на уже работающем приложении. Подробнее — в разделе про рантайм.
Два независимых API в одном приложении¶
Каждое агрегирующее приложение получает свой middleware — и свою независимую нумерацию версий.
app = FastAPI()
public_app = FastAPI(middleware=[middleware.Middleware(VersioningMiddleware)])
private_app = FastAPI(middleware=[middleware.Middleware(VersioningMiddleware)])
app.mount("/api/public", public_app)
app.mount("/api/private", private_app)
public_app.mount("/v1", FastAPI(api_version=1))
private_app.mount("/v1", FastAPI(api_version=1))
Полный разбор — в примере.
Версионировать WebSocket¶
WebSocket-роуты версионируются наравне с HTTP — с той же семантикой until и тем же затенением. Различается только способ пометки:
Скрыть унаследованные эндпоинты из Swagger¶
Если унаследованные роуты должны обслуживаться, но не показываться в /docs новых версий, отключите пересборку схемы:
Каждая версия сохранит ту схему, которую FastAPI собрал по её собственным роутам.
Отдавать номер версии клиенту¶
VersionInfo доступен в эндпоинте как обычная зависимость — например, чтобы положить границы поддержки в заголовок ответа: