fastapi-router-versioning 1.2.0__tar.gz → 1.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/bump-pre-commit-hooks.yml +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/PKG-INFO +15 -15
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/README.md +9 -9
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/callbacks-and-webhooks.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/deprecation-headers.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/multiple-routers.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/reverse-proxy-and-sub-apps.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/self-hosted-assets.md +2 -2
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/validation-error-status-code.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/version-discovery.md +1 -1
- fastapi_router_versioning-1.2.1/docs/assets/screenshots/migration-root.jpg +0 -0
- fastapi_router_versioning-1.2.1/docs/assets/screenshots/swagger-v3.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/examples.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/how-it-works.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/index.md +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/lifecycle.md +20 -5
- fastapi_router_versioning-1.2.1/docs/migrating.md +64 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/release-notes.md +14 -0
- fastapi_router_versioning-1.2.1/docs_src/migration/adopt.py +22 -0
- fastapi_router_versioning-1.2.1/docs_src/migration/change_endpoint.py +26 -0
- fastapi_router_versioning-1.2.1/docs_src/migration/retire_unversioned.py +25 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/__init__.py +1 -1
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/mkdocs.yml +7 -6
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/pyproject.toml +5 -5
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/docs_screenshots.py +2 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/generate_readme.py +5 -5
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_docs_src_behavior.py +31 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/uv.lock +27 -27
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/dependabot.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/latest-changes.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/build-docs.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/create-draft-release.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/deploy-docs.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/detect-conflicts.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/guard-dependencies.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/pre-commit.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/prepare-release.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/publish.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/test-redistribute.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/test.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.github/workflows/zizmor.yml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.gitignore +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.pre-commit-config.yaml +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/.python-version +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/LICENSE +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/callback-hook.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/custom-url-format.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/index.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/latest-alias.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/advanced/openapi-hook.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/apple-touch-icon.png +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/favicon.ico +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/favicon.png +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/favicon.svg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/logo-header.svg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/logo.svg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/images/wordmark.png +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/latest-alias.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/quickstart-calver.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/quickstart-semver-v1.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/quickstart-semver-v2.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/redoc-v2.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/swagger-v1.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/swagger-v2.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/url-format-latest.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/url-format-v1.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/versions-dashboard.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/webhooks-v1.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/assets/screenshots/webhooks-v2.jpg +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/quickstart.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/reference.md +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs/stylesheets/extra.css +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/callback_hook.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/callbacks.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/custom_url_format.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/deprecation_headers.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/latest_alias.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/multiple_routers.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/openapi_hook.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/reverse_proxy.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/self_hosted_assets.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/validation_error_status_code.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/version_discovery.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/advanced/webhooks.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/lifecycle/legacy_route.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/quickstart/calver.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/docs_src/quickstart/semver.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/calver_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/dashboard_assets/versions_dashboard.css +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/dashboard_assets/versions_dashboard.html +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/deprecation_headers_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/download_static_assets.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/mounted_subapps_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/multi_router_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/openapi_hook_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/self_hosted_docs_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/semver_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/semver_major_only_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/validation_override_integration_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/versions_dashboard_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/versions_dashboard_hook_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/examples/webhook_versioning_app.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_builder.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_compat.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_dashboard.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_deprecation.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_docs.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_lifecycle.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_registry.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_scheme.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/_versions.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/py.typed +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/fastapi_router_versioning/versioner.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/overrides/main.html +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/build_icons.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/docs-build.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/docs.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/format.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/lint.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/prepare_release.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/test-cov-html.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/test-cov.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/test.sh +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/__init__.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_calver.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_docs_src.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_examples.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_fastapi_integration.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_prepare_release.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_public_signature_docs.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_readme.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_semver.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_deprecation_headers.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_docs.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_errors.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_lifecycle.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_versions_dashboard.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_versions_route.py +0 -0
- {fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_versioner_webhooks.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fastapi-router-versioning
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Router-based API versioning for FastAPI, with per-version docs and a declarative route lifecycle.
|
|
5
|
-
Project-URL: Homepage, https://
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
-
Project-URL: Documentation, https://
|
|
9
|
-
Project-URL: Changelog, https://
|
|
5
|
+
Project-URL: Homepage, https://fastapi-router-versioning.matblack81.com/
|
|
6
|
+
Project-URL: Repository, https://github.com/matblack81/fastapi-router-versioning
|
|
7
|
+
Project-URL: Issues, https://github.com/matblack81/fastapi-router-versioning/issues
|
|
8
|
+
Project-URL: Documentation, https://fastapi-router-versioning.matblack81.com/
|
|
9
|
+
Project-URL: Changelog, https://fastapi-router-versioning.matblack81.com/release-notes/
|
|
10
10
|
Author-email: Matteo Nieddu <mat81black@gmail.com>
|
|
11
11
|
License-Expression: MIT
|
|
12
12
|
License-File: LICENSE
|
|
@@ -31,24 +31,24 @@ Requires-Dist: fastapi!=0.137.0,!=0.137.1,>=0.120.0
|
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
32
|
|
|
33
33
|
<p align="center">
|
|
34
|
-
<img src="https://raw.githubusercontent.com/
|
|
34
|
+
<img src="https://raw.githubusercontent.com/matblack81/fastapi-router-versioning/main/docs/assets/images/logo.svg" alt="FastAPI Router Versioning logo" width="128">
|
|
35
35
|
</p>
|
|
36
36
|
|
|
37
37
|
<h1 align="center">
|
|
38
|
-
<img src="https://raw.githubusercontent.com/
|
|
38
|
+
<img src="https://raw.githubusercontent.com/matblack81/fastapi-router-versioning/main/docs/assets/images/wordmark.png" alt="FastAPI Router Versioning" width="480">
|
|
39
39
|
</h1>
|
|
40
40
|
|
|
41
41
|
<p align="center">
|
|
42
|
-
<a href="https://github.com/
|
|
43
|
-
<a href="https://codecov.io/github/
|
|
42
|
+
<a href="https://github.com/matblack81/fastapi-router-versioning/actions"><img src="https://github.com/matblack81/fastapi-router-versioning/workflows/Test/badge.svg" alt="Build Status"></a>
|
|
43
|
+
<a href="https://codecov.io/github/matblack81/fastapi-router-versioning"><img src="https://codecov.io/github/matblack81/fastapi-router-versioning/graph/badge.svg?token=4WQ63Q7ESY" alt="codecov"></a>
|
|
44
44
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/v/fastapi-router-versioning?color=%2334D058&label=pypi%20package" alt="pypi package"></a>
|
|
45
45
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/pyversions/fastapi-router-versioning.svg?color=%2334D058" alt="Supported Python versions"></a>
|
|
46
|
-
<a href="https://github.com/
|
|
46
|
+
<a href="https://github.com/matblack81/fastapi-router-versioning/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT"></a>
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
49
|
Running multiple API versions side by side usually means duplicating routers, hand-rolling prefixes, or branching on request paths. `RouterVersioner` does it declaratively instead: annotate each route with the version it belongs to, and it generates the URL prefixes, the per-version OpenAPI schema, and the docs, without moving anything else in your app.
|
|
50
50
|
|
|
51
|
-
Documentation: https://
|
|
51
|
+
Documentation: https://fastapi-router-versioning.matblack81.com/
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
@@ -122,16 +122,16 @@ RouterVersioner(
|
|
|
122
122
|
).versionize()
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
CalVer, the route lifecycle, the parameter reference and the advanced options are in the [documentation](https://
|
|
125
|
+
CalVer, the route lifecycle, the parameter reference and the advanced options are in the [documentation](https://fastapi-router-versioning.matblack81.com/).
|
|
126
126
|
|
|
127
127
|
---
|
|
128
128
|
|
|
129
129
|
## Release Notes
|
|
130
130
|
|
|
131
|
-
[RELEASE_NOTES](https://github.com/
|
|
131
|
+
[RELEASE_NOTES](https://github.com/matblack81/fastapi-router-versioning/blob/main/docs/release-notes.md)
|
|
132
132
|
|
|
133
133
|
---
|
|
134
134
|
|
|
135
135
|
## License
|
|
136
136
|
|
|
137
|
-
[MIT](https://github.com/
|
|
137
|
+
[MIT](https://github.com/matblack81/fastapi-router-versioning/blob/main/LICENSE)
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/
|
|
2
|
+
<img src="https://raw.githubusercontent.com/matblack81/fastapi-router-versioning/main/docs/assets/images/logo.svg" alt="FastAPI Router Versioning logo" width="128">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">
|
|
6
|
-
<img src="https://raw.githubusercontent.com/
|
|
6
|
+
<img src="https://raw.githubusercontent.com/matblack81/fastapi-router-versioning/main/docs/assets/images/wordmark.png" alt="FastAPI Router Versioning" width="480">
|
|
7
7
|
</h1>
|
|
8
8
|
|
|
9
9
|
<p align="center">
|
|
10
|
-
<a href="https://github.com/
|
|
11
|
-
<a href="https://codecov.io/github/
|
|
10
|
+
<a href="https://github.com/matblack81/fastapi-router-versioning/actions"><img src="https://github.com/matblack81/fastapi-router-versioning/workflows/Test/badge.svg" alt="Build Status"></a>
|
|
11
|
+
<a href="https://codecov.io/github/matblack81/fastapi-router-versioning"><img src="https://codecov.io/github/matblack81/fastapi-router-versioning/graph/badge.svg?token=4WQ63Q7ESY" alt="codecov"></a>
|
|
12
12
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/v/fastapi-router-versioning?color=%2334D058&label=pypi%20package" alt="pypi package"></a>
|
|
13
13
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/pyversions/fastapi-router-versioning.svg?color=%2334D058" alt="Supported Python versions"></a>
|
|
14
|
-
<a href="https://github.com/
|
|
14
|
+
<a href="https://github.com/matblack81/fastapi-router-versioning/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT"></a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
17
|
Running multiple API versions side by side usually means duplicating routers, hand-rolling prefixes, or branching on request paths. `RouterVersioner` does it declaratively instead: annotate each route with the version it belongs to, and it generates the URL prefixes, the per-version OpenAPI schema, and the docs, without moving anything else in your app.
|
|
18
18
|
|
|
19
|
-
Documentation: https://
|
|
19
|
+
Documentation: https://fastapi-router-versioning.matblack81.com/
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
@@ -90,16 +90,16 @@ RouterVersioner(
|
|
|
90
90
|
).versionize()
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
-
CalVer, the route lifecycle, the parameter reference and the advanced options are in the [documentation](https://
|
|
93
|
+
CalVer, the route lifecycle, the parameter reference and the advanced options are in the [documentation](https://fastapi-router-versioning.matblack81.com/).
|
|
94
94
|
|
|
95
95
|
---
|
|
96
96
|
|
|
97
97
|
## Release Notes
|
|
98
98
|
|
|
99
|
-
[RELEASE_NOTES](https://github.com/
|
|
99
|
+
[RELEASE_NOTES](https://github.com/matblack81/fastapi-router-versioning/blob/main/docs/release-notes.md)
|
|
100
100
|
|
|
101
101
|
---
|
|
102
102
|
|
|
103
103
|
## License
|
|
104
104
|
|
|
105
|
-
[MIT](https://github.com/
|
|
105
|
+
[MIT](https://github.com/matblack81/fastapi-router-versioning/blob/main/LICENSE)
|
|
@@ -19,7 +19,7 @@ each definition:
|
|
|
19
19
|
--8<-- "docs_src/advanced/webhooks.py:snippet"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
In [`webhook_versioning_app.py`](https://github.com/
|
|
22
|
+
In [`webhook_versioning_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/webhook_versioning_app.py), which follows this pattern, v1.0 lists two webhooks and v2.0 only `order-created`, with its v2 definition (the example's second webhook is `payment-received` rather than `payment-failed`):
|
|
23
23
|
|
|
24
24
|
=== "v1.0"
|
|
25
25
|
|
|
@@ -33,4 +33,4 @@ config). `versionize()` raises `ValueError` if a route's `remove_in` date preced
|
|
|
33
33
|
This adds nothing to `@api_version`: the lifecycle stays on the route, the dates stay on the
|
|
34
34
|
versioner. `Deprecation` and `Sunset` are only set if the response doesn't already carry them:
|
|
35
35
|
a route that sets its own keeps it. The `Link` field is sent alongside any the route already
|
|
36
|
-
emits (RFC 8288: multiple `Link` fields combine). See [`deprecation_headers_app.py`](https://github.com/
|
|
36
|
+
emits (RFC 8288: multiple `Link` fields combine). See [`deprecation_headers_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/deprecation_headers_app.py).
|
|
@@ -15,7 +15,7 @@ Sharing one app across several `RouterVersioner` instances only makes sense for
|
|
|
15
15
|
mixing `version_format` values, SemVer for one group of routes and CalVer for another, on
|
|
16
16
|
the same app. Splitting modules that share a `version_format` doesn't need a second instance;
|
|
17
17
|
pass them all to one `RouterVersioner` via `routers=[...]` instead (see
|
|
18
|
-
[`multi_router_app.py`](https://github.com/
|
|
18
|
+
[`multi_router_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/multi_router_app.py)).
|
|
19
19
|
If you do share an app across instances, one rule is enforced: every instance needs
|
|
20
20
|
its own `prefix_format`/`latest_prefix`. Two instances that resolve to the same prefix would
|
|
21
21
|
otherwise overwrite each other's docs/openapi routes at the same path; this raises
|
|
@@ -14,4 +14,4 @@ The ASGI `root_path` FastAPI sets when an app runs behind a proxy or is mounted
|
|
|
14
14
|
A mounted sub-application is a separate `FastAPI()` instance, so a `RouterVersioner` attached to
|
|
15
15
|
it is entirely independent from one attached to the parent, or to another sub-application, with
|
|
16
16
|
no prefix coordination needed.
|
|
17
|
-
See [`examples/mounted_subapps_app.py`](https://github.com/
|
|
17
|
+
See [`examples/mounted_subapps_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/mounted_subapps_app.py).
|
|
@@ -11,5 +11,5 @@ copies for air-gapped or restricted-network deployments:
|
|
|
11
11
|
--8<-- "docs_src/advanced/self_hosted_assets.py:snippet"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
[`examples/download_static_assets.py`](https://github.com/
|
|
15
|
-
[`examples/self_hosted_docs_app.py`](https://github.com/
|
|
14
|
+
[`examples/download_static_assets.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/download_static_assets.py) downloads the required files in one step;
|
|
15
|
+
[`examples/self_hosted_docs_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/self_hosted_docs_app.py) wires them into a full app.
|
|
@@ -19,4 +19,4 @@ uv add fastapi-validation-override
|
|
|
19
19
|
--8<-- "docs_src/advanced/validation_error_status_code.py:snippet"
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
See [`examples/validation_override_integration_app.py`](https://github.com/
|
|
22
|
+
See [`examples/validation_override_integration_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/validation_override_integration_app.py).
|
|
@@ -46,4 +46,4 @@ if you want them).
|
|
|
46
46
|
|
|
47
47
|

|
|
48
48
|
|
|
49
|
-
The built-in dashboard, from [`versions_dashboard_app.py`](https://github.com/
|
|
49
|
+
The built-in dashboard, from [`versions_dashboard_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/versions_dashboard_app.py).
|
|
Binary file
|
|
@@ -128,4 +128,4 @@ Custom validation error status code via `fastapi-validation-override` and `opena
|
|
|
128
128
|
|
|
129
129
|
## Support files
|
|
130
130
|
|
|
131
|
-
[`download_static_assets.py`](https://github.com/
|
|
131
|
+
[`download_static_assets.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/download_static_assets.py) downloads the Swagger UI and ReDoc files used by `self_hosted_docs_app.py`, and the [`dashboard_assets/`](https://github.com/matblack81/fastapi-router-versioning/tree/main/examples/dashboard_assets) folder holds the template and stylesheet of `versions_dashboard_hook_app.py`.
|
|
@@ -22,7 +22,7 @@ Every version mentioned by any route, as `version`, `deprecate_in` or `remove_in
|
|
|
22
22
|
|
|
23
23
|
Because the key is the path *and* the method, one method of a route can be replaced while the others carry on, and a version that only removes routes still exists, with no routes at all if nothing else is active.
|
|
24
24
|
|
|
25
|
-
For [`semver_app.py`](https://github.com/
|
|
25
|
+
For [`semver_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/semver_app.py) this gives:
|
|
26
26
|
|
|
27
27
|
| Version | Routes served |
|
|
28
28
|
|---|---|
|
|
@@ -19,7 +19,7 @@ Running multiple API versions side by side usually means duplicating routers, ha
|
|
|
19
19
|
|
|
20
20
|
## What you get
|
|
21
21
|
|
|
22
|
-
Every version gets its own Swagger UI, ReDoc and `openapi.json`, listing only the routes active in that version. These screenshots come from [`semver_app.py`](https://github.com/
|
|
22
|
+
Every version gets its own Swagger UI, ReDoc and `openapi.json`, listing only the routes active in that version. These screenshots come from [`semver_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/semver_app.py), where `/lifecycle` and `/legacy-notice` are deprecated in v2.0, `/newcomer` is added in v2.0, and a dedicated route takes over `POST /settings`.
|
|
23
23
|
|
|
24
24
|
=== "Swagger UI, v1.0"
|
|
25
25
|
|
|
@@ -43,17 +43,32 @@ ever turns deprecation *on* for versions at or after its boundary; it never turn
|
|
|
43
43
|
|
|
44
44
|
A route with `methods=["GET", "POST"]` can have just one of its methods taken over by a
|
|
45
45
|
dedicated route in a later version; the other method keeps being served by the original
|
|
46
|
-
route. See [`semver_app.py`](https://github.com/
|
|
46
|
+
route. See [`semver_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/semver_app.py)
|
|
47
47
|
for a working example.
|
|
48
48
|
|
|
49
49
|
## In the generated docs
|
|
50
50
|
|
|
51
51
|
In each version's Swagger UI and ReDoc, a route in its deprecation window is struck through, a route
|
|
52
|
-
removed from a version is absent, and a route introduced later appears only from that version.
|
|
53
|
-
v2.0 of [`semver_app.py`](https://github.com/
|
|
54
|
-
`/lifecycle` and `/legacy-notice` are deprecated from v2.0, and `/newcomer` is introduced in it.
|
|
52
|
+
removed from a version is absent, and a route introduced later appears only from that version. These are
|
|
53
|
+
v1.0, v2.0 and v3.0 of [`semver_app.py`](https://github.com/matblack81/fastapi-router-versioning/blob/main/examples/semver_app.py):
|
|
55
54
|
|
|
56
|
-
|
|
55
|
+
=== "v1.0"
|
|
56
|
+
|
|
57
|
+
`/lifecycle` and `/legacy-notice` are active, and `/newcomer` and `/future` don't exist yet.
|
|
58
|
+
|
|
59
|
+
{ loading=lazy }
|
|
60
|
+
|
|
61
|
+
=== "v2.0"
|
|
62
|
+
|
|
63
|
+
`/lifecycle` and `/legacy-notice` are deprecated from v2.0, and `/newcomer` is introduced in it.
|
|
64
|
+
|
|
65
|
+
{ loading=lazy }
|
|
66
|
+
|
|
67
|
+
=== "v3.0"
|
|
68
|
+
|
|
69
|
+
`/lifecycle` is removed. `/legacy-notice` has no `remove_in`, so it stays, still deprecated, and `/future` is introduced.
|
|
70
|
+
|
|
71
|
+
{ loading=lazy }
|
|
57
72
|
|
|
58
73
|
## Deprecation headers
|
|
59
74
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Add RouterVersioner to a FastAPI app that already has clients, without breaking the URLs they call.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Adding it to an existing app
|
|
6
|
+
|
|
7
|
+
You don't have to rewrite anything to start. A route without `@api_version` is given
|
|
8
|
+
`default_version`, which is v1.0 under SemVer, so the app you have today is already "version 1".
|
|
9
|
+
The steps below keep the unversioned URLs working while your clients move to the versioned ones.
|
|
10
|
+
|
|
11
|
+
## 1. Versionize what you have
|
|
12
|
+
|
|
13
|
+
This is an ordinary app, with its router included once:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
--8<-- "docs_src/migration/adopt.py:routes"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Pass the same router to `RouterVersioner` and call `.versionize()`, leaving everything above as it is:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
--8<-- "docs_src/migration/adopt.py:versionize"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Nothing is decorated, so `GET /items` is mounted as `GET /v1_0/items`, with its own docs at `/v1_0/docs`.
|
|
26
|
+
`GET /items` keeps answering too: `app.include_router(router)` is still there, and `RouterVersioner` doesn't touch it.
|
|
27
|
+
|
|
28
|
+
## 2. Change an endpoint in a new version
|
|
29
|
+
|
|
30
|
+
Declare the new one at a higher version, next to the old one. The old function stays exactly as it was:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
--8<-- "docs_src/migration/change_endpoint.py:snippet"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
| URL | Answered by |
|
|
37
|
+
|-----|-------------|
|
|
38
|
+
| `/items` | the original function, as before |
|
|
39
|
+
| `/v1_0/items` | the original function |
|
|
40
|
+
| `/v2_0/items` | the new function |
|
|
41
|
+
|
|
42
|
+
!!! note "The unversioned URL does not follow the new version"
|
|
43
|
+
|
|
44
|
+
`/items` is served by the router you included yourself, and FastAPI answers with the first route that matches: the original function. It never moves to v2.0, so clients still on it see no change.
|
|
45
|
+
|
|
46
|
+
The app's own docs, at `/docs`, list the unversioned URL together with every versioned one, while each version's docs list only its own routes:
|
|
47
|
+
|
|
48
|
+
{ loading=lazy }
|
|
49
|
+
|
|
50
|
+
!!! warning "Don't read the unversioned URL from `/docs`"
|
|
51
|
+
|
|
52
|
+
FastAPI keeps one operation per path and method in a schema, the last one declared. So `/docs` describes `/items` with the v2.0 function ("Get Items V2" above), while requests to `/items` are answered by the original one. Use `/v1_0/docs` and `/v2_0/docs` as the reference for what each version returns.
|
|
53
|
+
|
|
54
|
+
## 3. Retire the unversioned URLs
|
|
55
|
+
|
|
56
|
+
Once your clients call the versioned URLs, remove `app.include_router(router)`. If you still want a URL that always means "the newest", `latest_prefix` adds one:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
--8<-- "docs_src/migration/retire_unversioned.py:snippet"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`/items` now answers 404, and `/latest/items` serves whichever version is highest: see the [latest alias](advanced/latest-alias.md).
|
|
63
|
+
|
|
64
|
+
Call `.versionize()` once, after every route is declared, as in the [Quick start](quickstart.md). To take a route out of a version later, or to mark it deprecated first, see the [route lifecycle](lifecycle.md).
|
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Latest Changes
|
|
4
4
|
|
|
5
|
+
## 1.2.1 (2026-10-15)
|
|
6
|
+
|
|
7
|
+
### Docs
|
|
8
|
+
|
|
9
|
+
* 🖼️ Adjust logo dimensions in README and script by removing height attribute. PR [#118](https://github.com/matblack81/fastapi-router-versioning/pull/118) by [@matblack81](https://github.com/matblack81).
|
|
10
|
+
* 📝 Add a guide to adopting versioning in an existing app. PR [#116](https://github.com/mat81black/fastapi-router-versioning/pull/116) by [@mat81black](https://github.com/mat81black).
|
|
11
|
+
* 📝 Add v1.0, v2.0 and v3.0 Swagger screenshots to the route lifecycle page. PR [#115](https://github.com/mat81black/fastapi-router-versioning/pull/115) by [@mat81black](https://github.com/mat81black).
|
|
12
|
+
|
|
13
|
+
### Internal
|
|
14
|
+
|
|
15
|
+
* 📝 Point documentation links to the new domain. PR [#117](https://github.com/matblack81/fastapi-router-versioning/pull/117) by [@matblack81](https://github.com/matblack81).
|
|
16
|
+
* ⬆ Bump annotated-doc from 0.0.4 to 0.0.5. PR [#114](https://github.com/mat81black/fastapi-router-versioning/pull/114) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
|
17
|
+
* ⬆ Bump the python-packages group with 2 updates. PR [#113](https://github.com/mat81black/fastapi-router-versioning/pull/113) by [@dependabot[bot]](https://github.com/apps/dependabot).
|
|
18
|
+
|
|
5
19
|
## 1.2.0 (2026-10-04)
|
|
6
20
|
|
|
7
21
|
### Docs
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from fastapi import APIRouter, FastAPI
|
|
2
|
+
from fastapi_router_versioning import RouterVersioner, VersionFormat
|
|
3
|
+
|
|
4
|
+
app = FastAPI()
|
|
5
|
+
router = APIRouter()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# --8<-- [start:routes]
|
|
9
|
+
@router.get("/items")
|
|
10
|
+
def get_items():
|
|
11
|
+
return {"items": ["a", "b"]}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
app.include_router(router)
|
|
15
|
+
# --8<-- [end:routes]
|
|
16
|
+
|
|
17
|
+
# --8<-- [start:versionize]
|
|
18
|
+
RouterVersioner(
|
|
19
|
+
app=app, routers=router,
|
|
20
|
+
version_format=VersionFormat.SEMVER
|
|
21
|
+
).versionize()
|
|
22
|
+
# --8<-- [end:versionize]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from fastapi import APIRouter, FastAPI
|
|
2
|
+
from fastapi_router_versioning import RouterVersioner, VersionFormat, api_version
|
|
3
|
+
|
|
4
|
+
app = FastAPI()
|
|
5
|
+
router = APIRouter()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@router.get("/items")
|
|
9
|
+
def get_items():
|
|
10
|
+
return {"items": ["a", "b"]}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# --8<-- [start:snippet]
|
|
14
|
+
@router.get("/items")
|
|
15
|
+
@api_version((2, 0))
|
|
16
|
+
def get_items_v2():
|
|
17
|
+
return {"items": ["a", "b", "c"]}
|
|
18
|
+
# --8<-- [end:snippet]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
app.include_router(router)
|
|
22
|
+
|
|
23
|
+
RouterVersioner(
|
|
24
|
+
app=app, routers=router,
|
|
25
|
+
version_format=VersionFormat.SEMVER
|
|
26
|
+
).versionize()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from fastapi import APIRouter, FastAPI
|
|
2
|
+
from fastapi_router_versioning import RouterVersioner, VersionFormat, api_version
|
|
3
|
+
|
|
4
|
+
app = FastAPI()
|
|
5
|
+
router = APIRouter()
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@router.get("/items")
|
|
9
|
+
def get_items():
|
|
10
|
+
return {"items": ["a", "b"]}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@router.get("/items")
|
|
14
|
+
@api_version((2, 0))
|
|
15
|
+
def get_items_v2():
|
|
16
|
+
return {"items": ["a", "b", "c"]}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# --8<-- [start:snippet]
|
|
20
|
+
RouterVersioner(
|
|
21
|
+
app=app, routers=router,
|
|
22
|
+
version_format=VersionFormat.SEMVER,
|
|
23
|
+
latest_prefix="/latest",
|
|
24
|
+
).versionize()
|
|
25
|
+
# --8<-- [end:snippet]
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
site_name: FastAPI Router Versioning
|
|
2
2
|
site_description: Router-based API versioning for FastAPI, with per-version docs and a declarative route lifecycle.
|
|
3
|
-
site_url: https://
|
|
4
|
-
repo_url: https://github.com/
|
|
5
|
-
repo_name:
|
|
6
|
-
copyright: Copyright © 2026 Matteo Nieddu · <a href="https://github.com/
|
|
3
|
+
site_url: https://fastapi-router-versioning.matblack81.com/
|
|
4
|
+
repo_url: https://github.com/matblack81/fastapi-router-versioning
|
|
5
|
+
repo_name: matblack81/fastapi-router-versioning
|
|
6
|
+
copyright: Copyright © 2026 Matteo Nieddu · <a href="https://github.com/matblack81/fastapi-router-versioning/blob/main/LICENSE">MIT License</a>
|
|
7
7
|
edit_uri: edit/main/docs/
|
|
8
8
|
|
|
9
9
|
theme:
|
|
@@ -51,13 +51,13 @@ theme:
|
|
|
51
51
|
extra:
|
|
52
52
|
social:
|
|
53
53
|
- icon: fontawesome/brands/github
|
|
54
|
-
link: https://github.com/
|
|
54
|
+
link: https://github.com/matblack81/fastapi-router-versioning
|
|
55
55
|
name: Source code on GitHub
|
|
56
56
|
- icon: fontawesome/brands/python
|
|
57
57
|
link: https://pypi.org/project/fastapi-router-versioning/
|
|
58
58
|
name: fastapi-router-versioning on PyPI
|
|
59
59
|
- icon: fontawesome/solid/bug
|
|
60
|
-
link: https://github.com/
|
|
60
|
+
link: https://github.com/matblack81/fastapi-router-versioning/issues
|
|
61
61
|
name: Report an issue
|
|
62
62
|
|
|
63
63
|
extra_css:
|
|
@@ -67,6 +67,7 @@ nav:
|
|
|
67
67
|
- Home: index.md
|
|
68
68
|
- Guide:
|
|
69
69
|
- Quick start: quickstart.md
|
|
70
|
+
- Adding it to an existing app: migrating.md
|
|
70
71
|
- Route lifecycle: lifecycle.md
|
|
71
72
|
- How it works: how-it-works.md
|
|
72
73
|
- Advanced options:
|
|
@@ -36,11 +36,11 @@ dependencies = [
|
|
|
36
36
|
]
|
|
37
37
|
|
|
38
38
|
[project.urls]
|
|
39
|
-
Homepage = "https://
|
|
40
|
-
Repository = "https://github.com/
|
|
41
|
-
Issues = "https://github.com/
|
|
42
|
-
Documentation = "https://
|
|
43
|
-
Changelog = "https://
|
|
39
|
+
Homepage = "https://fastapi-router-versioning.matblack81.com/"
|
|
40
|
+
Repository = "https://github.com/matblack81/fastapi-router-versioning"
|
|
41
|
+
Issues = "https://github.com/matblack81/fastapi-router-versioning/issues"
|
|
42
|
+
Documentation = "https://fastapi-router-versioning.matblack81.com/"
|
|
43
|
+
Changelog = "https://fastapi-router-versioning.matblack81.com/release-notes/"
|
|
44
44
|
|
|
45
45
|
[dependency-groups]
|
|
46
46
|
dev = [
|
{fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/docs_screenshots.py
RENAMED
|
@@ -46,11 +46,13 @@ class Shot:
|
|
|
46
46
|
SHOTS = [
|
|
47
47
|
Shot("swagger-v1", "examples/semver_app.py", "/v1_0/docs", "swagger"),
|
|
48
48
|
Shot("swagger-v2", "examples/semver_app.py", "/v2_0/docs", "swagger"),
|
|
49
|
+
Shot("swagger-v3", "examples/semver_app.py", "/v3_0/docs", "swagger"),
|
|
49
50
|
Shot("redoc-v2", "examples/semver_app.py", "/v2_0/redoc", "redoc"),
|
|
50
51
|
Shot("versions-dashboard", "examples/versions_dashboard_app.py", "/dashboard", "dashboard"),
|
|
51
52
|
Shot("quickstart-semver-v1", "docs_src/quickstart/semver.py", "/v1_0/docs", "swagger"),
|
|
52
53
|
Shot("quickstart-semver-v2", "docs_src/quickstart/semver.py", "/v2_0/docs", "swagger"),
|
|
53
54
|
Shot("quickstart-calver", "docs_src/quickstart/calver.py", "/2025-01-01/docs", "swagger"),
|
|
55
|
+
Shot("migration-root", "docs_src/migration/change_endpoint.py", "/docs", "swagger"),
|
|
54
56
|
Shot("url-format-v1", "docs_src/advanced/custom_url_format.py", "/v1/docs", "swagger"),
|
|
55
57
|
Shot("url-format-latest", "docs_src/advanced/custom_url_format.py", "/latest/docs", "swagger"),
|
|
56
58
|
Shot("latest-alias", "docs_src/advanced/latest_alias.py", "/latest/docs", "swagger"),
|
{fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/scripts/generate_readme.py
RENAMED
|
@@ -17,12 +17,12 @@ from pathlib import Path
|
|
|
17
17
|
|
|
18
18
|
ROOT = Path(__file__).parent.parent
|
|
19
19
|
README = ROOT / "README.md"
|
|
20
|
-
SITE_URL = "https://
|
|
21
|
-
REPO_URL = "https://github.com/
|
|
22
|
-
ASSETS_URL = "https://raw.githubusercontent.com/
|
|
20
|
+
SITE_URL = "https://fastapi-router-versioning.matblack81.com/"
|
|
21
|
+
REPO_URL = "https://github.com/matblack81/fastapi-router-versioning"
|
|
22
|
+
ASSETS_URL = "https://raw.githubusercontent.com/matblack81/fastapi-router-versioning/main/docs/assets/images"
|
|
23
23
|
|
|
24
24
|
HEADER = f"""<p align="center">
|
|
25
|
-
<img src="{ASSETS_URL}/logo.svg" alt="FastAPI Router Versioning logo" width="128"
|
|
25
|
+
<img src="{ASSETS_URL}/logo.svg" alt="FastAPI Router Versioning logo" width="128">
|
|
26
26
|
</p>
|
|
27
27
|
|
|
28
28
|
<h1 align="center">
|
|
@@ -31,7 +31,7 @@ HEADER = f"""<p align="center">
|
|
|
31
31
|
|
|
32
32
|
<p align="center">
|
|
33
33
|
<a href="{REPO_URL}/actions"><img src="{REPO_URL}/workflows/Test/badge.svg" alt="Build Status"></a>
|
|
34
|
-
<a href="https://codecov.io/github/
|
|
34
|
+
<a href="https://codecov.io/github/matblack81/fastapi-router-versioning"><img src="https://codecov.io/github/matblack81/fastapi-router-versioning/graph/badge.svg?token=4WQ63Q7ESY" alt="codecov"></a>
|
|
35
35
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/v/fastapi-router-versioning?color=%2334D058&label=pypi%20package" alt="pypi package"></a>
|
|
36
36
|
<a href="https://pypi.org/project/fastapi-router-versioning/"><img src="https://img.shields.io/pypi/pyversions/fastapi-router-versioning.svg?color=%2334D058" alt="Supported Python versions"></a>
|
|
37
37
|
<a href="{REPO_URL}/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT"></a>
|
{fastapi_router_versioning-1.2.0 → fastapi_router_versioning-1.2.1}/tests/test_docs_src_behavior.py
RENAMED
|
@@ -176,3 +176,34 @@ def test_route_callbacks_are_carried_into_the_version() -> None:
|
|
|
176
176
|
client = TestClient(load("advanced/callbacks").app)
|
|
177
177
|
|
|
178
178
|
assert schema(client, "/v1_0")["paths"]["/v1_0/items"]["post"]["callbacks"]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_migration_adopt_keeps_the_unversioned_url_and_mounts_v1() -> None:
|
|
182
|
+
client = TestClient(load("migration/adopt").app)
|
|
183
|
+
|
|
184
|
+
assert client.get("/items").json() == {"items": ["a", "b"]}
|
|
185
|
+
assert client.get("/v1_0/items").json() == {"items": ["a", "b"]}
|
|
186
|
+
assert client.get("/v1_0/docs").status_code == 200
|
|
187
|
+
assert client.get("/v2_0/items").status_code == 404
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def test_migration_unversioned_url_does_not_follow_the_new_version() -> None:
|
|
191
|
+
client = TestClient(load("migration/change_endpoint").app)
|
|
192
|
+
|
|
193
|
+
assert client.get("/items").json() == {"items": ["a", "b"]}
|
|
194
|
+
assert client.get("/v1_0/items").json() == {"items": ["a", "b"]}
|
|
195
|
+
assert client.get("/v2_0/items").json() == {"items": ["a", "b", "c"]}
|
|
196
|
+
# the app's own schema keeps the last operation declared for /items, while requests get the first
|
|
197
|
+
root_schema = schema(client, "")
|
|
198
|
+
assert list(root_schema["paths"]) == ["/items", "/v1_0/items", "/v2_0/items"]
|
|
199
|
+
assert root_schema["paths"]["/items"]["get"]["summary"] == "Get Items V2"
|
|
200
|
+
assert list(schema(client, "/v1_0")["paths"]) == ["/v1_0/items"]
|
|
201
|
+
assert list(schema(client, "/v2_0")["paths"]) == ["/v2_0/items"]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def test_migration_retiring_the_unversioned_url_leaves_latest() -> None:
|
|
205
|
+
client = TestClient(load("migration/retire_unversioned").app)
|
|
206
|
+
|
|
207
|
+
assert client.get("/items").status_code == 404
|
|
208
|
+
assert client.get("/v1_0/items").json() == {"items": ["a", "b"]}
|
|
209
|
+
assert client.get("/latest/items").json() == {"items": ["a", "b", "c"]}
|