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.137.0 and 0.137.1 are excluded). fastapi is the only runtime dependency. Upgrading from 0.4.x? Switch your version declarations to versionize first — see the migration notes.
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. versionize(app, N) declares a sub-application's version. 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, versionize
app = FastAPI()
app_v1 = versionize(FastAPI(), 1) # the version number is an int; 0 is valid
app_v2 = versionize(FastAPI(), 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.5.0
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.5.0.tar.gz | 13.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_easy_versioning-0.5.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.3 kB
Release files / fastapi_easy_versioning-0.5.0.tar.gz
| Download URL | fastapi_easy_versioning-0.5.0.tar.gz |
|---|---|
| Size | 13.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d73ad62dabb1513158f25bdcdac691a3a7da8ddcffe7c3ea4a4e8c59089128a7
|
|
BLAKE2b-256 checksum How to use checksums |
bb7719315bea255acde65641eae553f6f19183fb2e28dc9082dd4ae783144eab
|
| 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.5.0-py3-none-any.whl
| Download URL | fastapi_easy_versioning-0.5.0-py3-none-any.whl |
|---|---|
| Size | 13.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
dd4553c41e0a0dc1048a93c3bbbd8dc0eabb75847d8d2be588307512ba5ef280
|
|
BLAKE2b-256 checksum How to use checksums |
3b0f506547538ad998491a19a643fb4a9799bcea64886e01e74c3c0b0c3cae62
|
| 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.5.0
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.