fastapi-easy-versioning
English · Русский
Versioned APIs for FastAPI — one sub-application per version, automatic inheritance of endpoints from older versions into newer ones, and an up-to-date OpenAPI schema for every version.
Once an API lives in several versions, routes have to be copied between them by hand: /v2 must serve everything /v1 served, minus what was deliberately dropped. The copies drift apart, /v1/docs and /v2/docs start lying, and "which versions is this endpoint even in?" becomes a question for git blame. This package makes the availability range a property of the endpoint: declare it once, mark it with a dependency, and it shows up in every later version by itself.
app = FastAPI()
app.add_middleware(VersioningMiddleware)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
@app_v1.get("/items", dependencies=[Depends(versioning())])
def items() -> list[Item]:
return get_items()
Declared once in v1 — served at /v1/items and /v2/items, and present in both versions' Swagger. No duplicated route, no hand-maintained schema.
Install
pip install fastapi-easy-versioning
Requires Python 3.10+ and FastAPI ≥ 0.95, < 0.145 (0.137.0 and 0.137.1 are excluded). fastapi is the only runtime dependency. Declaring a version with FastAPI(api_version=N) is deprecated since 0.4.2: 0.5.0 replaces it with a new interface that also supports FastAPI 0.145+.
How to use it
Versioning is built from two pieces that work only together.
1. Mount one sub-application per version and add the middleware. The middleware goes on the aggregating application — the one that directly mounts the versions, never on the versions themselves.
from fastapi import Depends, FastAPI
from fastapi_easy_versioning import VersioningMiddleware, versioning
app = FastAPI()
app_v1 = FastAPI(api_version=1) # the version number is an int; 0 is valid
app_v2 = FastAPI(api_version=2)
app.mount("/v1", app_v1)
app.mount("/v2", app_v2)
app.add_middleware(VersioningMiddleware)
2. Mark the endpoints. Marking is opt-in: an endpoint without the dependency stays in its own version only.
@app_v1.get("/only-v1", dependencies=[Depends(versioning(until=1))])
def only_v1() -> str:
return "Available only in version v1"
@app_v1.get("/all-versions", dependencies=[Depends(versioning())])
def all_versions() -> str:
return "Available in all versions starting from v1"
@app_v2.get("/from-v2", dependencies=[Depends(versioning())])
def from_v2() -> str:
return "Available starting from v2 and in all future versions"
versioning() without until means "through the latest version", not "in this one only" — a common source of surprise. The dependency is accepted anywhere FastAPI accepts one, including APIRouter(dependencies=[...]) to version a whole router at once.
3. Read the version metadata where you need it. Injected into the signature, the same dependency yields the resolved range:
@app_v1.get("/where-am-i")
def where_am_i(version: Annotated[VersionInfo, Depends(versioning())]) -> str:
return f"Available from v{version.origin} through v{version.until}"
The result: /v1/only-v1 responds while /v2/only-v1 is a 404; /all-versions responds in both; /v2/from-v2 responds while /v1/from-v2 is a 404 — and each version's /docs shows exactly what that version serves.
Why it's cool
- Declare once, inherit forward — an endpoint declared in v1 is served by every later version, each with its own copy of the route.
- An exact availability range —
untilcaps the last version an endpoint lives in; several markers on one route resolve to the smallest. - Redefinition shadows — an endpoint of your own on the same path in a newer version replaces the inherited one, at runtime and in OpenAPI alike.
- Honest per-version docs — every version's OpenAPI schema is regenerated after inheritance, so Swagger never drifts from what is actually served.
- HTTP and WebSocket —
APIRouteandAPIWebSocketRouteare versioned with identical semantics, and shadowing is kind-aware. - Several independent APIs — public and private APIs in one application version separately, one middleware per aggregating app.
- Nothing but FastAPI — a single runtime dependency, fully typed (
py.typed), tested against FastAPI 0.95 through the latest on Python 3.10–3.14.
Documentation
📖 Full documentation — quickstart, the guide (dependency, middleware, recipes, limitations), runnable examples and an auto-generated API reference. Available in English and Russian.
License
MIT.
Metadata
Release files for fastapi-easy-versioning 0.4.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| fastapi_easy_versioning-0.4.2.tar.gz | 12.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_easy_versioning-0.4.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.8 kB
Release files / fastapi_easy_versioning-0.4.2.tar.gz
| Download URL | fastapi_easy_versioning-0.4.2.tar.gz |
|---|---|
| Size | 12.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
957a5c58f0765c27e62254afdce0689d78429c8e4f93c0d95c0364855c2aff54
|
|
BLAKE2b-256 checksum How to use checksums |
774d69ab7851cfedce3ee7fdabd9a0776c3c43595adab7340d79d4c0222cb5d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fastapi_easy_versioning-0.4.2-py3-none-any.whl
| Download URL | fastapi_easy_versioning-0.4.2-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
eeda904c260f0091987017438c5385511dd64b9ee77cb2dbe9d9269559f640b5
|
|
BLAKE2b-256 checksum How to use checksums |
8188e4d0c6bb5329d4bb65be604619b10626fe63acaf0859428fdad84e01863c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for fastapi-easy-versioning 0.4.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.