fastapi-easy-versioning¶
Версионированные API на FastAPI. Одно субприложение на версию, автоматическое наследование эндпоинтов из старых версий в новые и своя актуальная OpenAPI-схема у каждой версии.
Зачем это нужно¶
Когда API живёт в нескольких версиях, между ними приходится вручную копировать роуты: /v2 должен отдавать всё, что отдавал /v1, кроме того, что осознанно выпилили. Копии расползаются, /v1/docs и /v2/docs начинают врать, а «в какой версии этот эндпоинт вообще есть» становится вопросом к git blame.
fastapi-easy-versioning делает диапазон доступности свойством эндпоинта: объявляете его один раз, помечаете зависимостью — и он сам оказывается во всех последующих версиях.
app_v1 = FastAPI()
app_v2 = FastAPI()
@app_v1.get("/items")
def items_v1() -> list[Item]: # (1)!
return get_items()
@app_v2.get("/items")
def items_v2() -> list[Item]:
return get_items()
- Один и тот же эндпоинт, продублированный руками. С каждой новой версией копий становится больше, и однажды одну из них забудут обновить.
app = FastAPI()
app.add_middleware(VersioningMiddleware)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
@app_v1.get("/items", dependencies=[Depends(versioning())]) # (1)!
def items() -> list[Item]:
return get_items()
- Объявлен один раз в v1 — и доступен в v2 и во всех будущих версиях. Схема
/v2/docsсобирается сама.
@app_v1.get("/legacy", dependencies=[Depends(versioning(until=2))]) # (1)!
def legacy() -> str:
return "уйдёт после v2"
- Доступен в v1 и v2, в v3 его уже нет — ни в рантайме, ни в схеме. Подробнее в семантике
until.
Каждая версия остаётся обычным FastAPI-приложением: свой роутинг, свой /docs, свои dependency_overrides.
graph TD
A[Доступность по версиям]
A --> B[v1]
A --> C[v2]
B --> B1["/only-v1 ✓"]:::available
B --> B2["/all-versions ✓"]:::available
B --> B3["/from-v2 ✗"]:::missing
C --> C1["/only-v1 ✗"]:::missing
C --> C2["/all-versions ✓"]:::available
C --> C3["/from-v2 ✓"]:::available
classDef available fill:#90EE90,stroke:#333,color:#1b1b1b
classDef missing fill:#FFB6C1,stroke:#333,color:#1b1b1b
Возможности¶
-
Наследование между версиями
Эндпоинт объявляется один раз и сам оказывается во всех последующих версиях. Каждая версия получает собственную копию роута.
-
Точный диапазон доступности
untilзадаёт последнюю версию, в которой эндпоинт доступен. Без него — «до последней версии», включая ещё не созданные. -
Переопределение затеняет
Свой эндпоинт на том же пути в новой версии перекрывает унаследованный — и в рантайме, и в OpenAPI.
-
Честный
/docsу каждой версии
После наследования OpenAPI-схема каждой версии перестраивается, поэтому Swagger показывает ровно её состав.
-
HTTP и WebSocket
APIRouteиAPIWebSocketRouteверсионируются одинаково; метаданные версии читаются прямо в эндпоинте. -
Несколько независимых API
Public и private API в одном приложении версионируются раздельно — по одному middleware на каждое агрегирующее приложение.
Установка¶
Требования
- Python 3.10+
- FastAPI ≥ 0.95 (версии
0.137.0и0.137.1исключены — см. Ограничения) - Больше ничего:
fastapi— единственная рантайм-зависимость
Дальше¶
- Быстрый старт — рабочее приложение за минуту.
- Руководство — зависимость, middleware, рецепты, ограничения.
- Примеры — запускаемые приложения из репозитория.
- Справочник API — сигнатуры из docstrings.