FastAPI Easy Versioning
Библиотека для построения версионированного API на FastAPI. Каждая версия API — отдельное FastAPI-субприложение, смонтированное под общим приложением. Библиотека автоматически наследует эндпоинты из старых версий в новые и перестраивает OpenAPI-схему каждой версии, поэтому /docs каждой версии всегда показывает её полный актуальный состав.
Возможности
- Наследование эндпоинтов между версиями: эндпоинт объявляется один раз и доступен во всех последующих версиях.
- Точное управление диапазоном доступности через параметр
until. - Переопределение эндпоинта в новой версии затеняет унаследованный — и в рантайме, и в OpenAPI-схеме.
- Поддержка HTTP- и WebSocket-эндпоинтов.
- Чтение метаданных версионирования (
origin,until) прямо в эндпоинте. - Несколько независимых версионированных API в одном приложении.
- Единственная рантайм-зависимость —
fastapi(поддерживаются версии от 0.95 до новейших).
Установка
pip install fastapi-easy-versioning
Быстрый старт
Версионирование строится из двух частей, которые работают только вместе:
VersioningMiddleware— добавляется в приложение, монтирующее версии;versioning()— фабрика зависимостей, помечающая эндпоинт как версионированный.
from fastapi import FastAPI, Depends
from fastapi_easy_versioning import VersioningMiddleware, versioning
app = FastAPI()
app_v1 = FastAPI(api_version=1)
app_v2 = FastAPI(api_version=2)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
app.add_middleware(VersioningMiddleware)
@app_v1.get('/only-v1', dependencies=[Depends(versioning(until=1))])
def only_v1() -> str:
return "Я доступен только в версии v1"
@app_v1.get('/all-versions', dependencies=[Depends(versioning())])
def all_versions() -> str:
return "Я доступен во всех версиях, начиная с v1"
@app_v2.get('/from-v2', dependencies=[Depends(versioning())])
def from_v2() -> str:
return "Я доступен начиная с версии v2 и во всех последующих"
graph TD
A[Доступность по версиям]
A --> B[v1]
A --> C[v2]
B --> B1["/only-v1 ✓"]
B --> B2["/all-versions ✓"]
B --> B3["/from-v2 ✗"]
C --> C1["/only-v1 ✗"]
C --> C2["/all-versions ✓"]
C --> C3["/from-v2 ✓"]
style B1 fill:#90EE90
style B2 fill:#90EE90
style B3 fill:#FFB6C1
style C1 fill:#FFB6C1
style C2 fill:#90EE90
style C3 fill:#90EE90
В результате:
/v1/only-v1отвечает, а/v2/only-v1возвращает 404 — эндпоинт ограниченuntil=1./v1/all-versionsи/v2/all-versionsотвечают оба — эндпоинт объявлен вv1и унаследован вv2./v2/from-v2отвечает, а/v1/from-v2возвращает 404 — эндпоинт появился только вv2./v1/docsи/v2/docsпоказывают ровно те эндпоинты, которые доступны в соответствующей версии.
Как это работает
- Каждая версия — субприложение
FastAPI(api_version=N), смонтированное под общим приложением:app.mount("/v1", app_v1).api_versionдолжен быть целым числом. VersioningMiddlewareпри первом ASGI-событии (запуск сервера или первый запрос) один раз строит наследование: копирует помеченные эндпоинты из старых версий в новые и перестраивает OpenAPI-схему каждой версии.- Наследуются только эндпоинты с зависимостью
versioning(). Эндпоинт без неё остаётся только в той версии, где объявлен. - Каждая наследующая версия получает собственную копию роута — изменения одной версии не влияют на другие.
Разделы документации
- Зависимость
versioning— способы пометки эндпоинтов, семантикаuntil, чтение метаданных в эндпоинте. - Middleware — куда добавлять, как работает наследование, OpenAPI, добавление роутов в рантайме, совместимость с версиями FastAPI.
- Примеры: простое версионирование, несколько независимых API.