From 1f21b16e03260d6935c73fa609b7017357abaf34 Mon Sep 17 00:00:00 2001 From: Carson Crane Date: Wed, 28 Jun 2023 09:39:10 -0700 Subject: [PATCH 01/14] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20`deque`?= =?UTF-8?q?=20objects=20and=20children=20in=20`jsonable=5Fencoder`=20(#943?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/encoders.py | 4 ++-- tests/test_jsonable_encoder.py | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 2f95bcbf6..94f41bfa1 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -1,5 +1,5 @@ import dataclasses -from collections import defaultdict +from collections import defaultdict, deque from enum import Enum from pathlib import PurePath from types import GeneratorType @@ -124,7 +124,7 @@ def jsonable_encoder( ) encoded_dict[encoded_key] = encoded_value return encoded_dict - if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)): + if isinstance(obj, (list, set, frozenset, GeneratorType, tuple, deque)): encoded_list = [] for item in obj: encoded_list.append( diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index f4fdcf601..1f43c33c7 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -1,3 +1,4 @@ +from collections import deque from dataclasses import dataclass from datetime import datetime, timezone from enum import Enum @@ -237,3 +238,12 @@ def test_encode_model_with_path(model_with_path): def test_encode_root(): model = ModelWithRoot(__root__="Foo") assert jsonable_encoder(model) == "Foo" + + +def test_encode_deque_encodes_child_models(): + class Model(BaseModel): + test: str + + dq = deque([Model(test="test")]) + + assert jsonable_encoder(dq)[0]["test"] == "test" From 0f390cd4b57b47fb53989094dc87d18ce337058a Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 28 Jun 2023 16:39:44 +0000 Subject: [PATCH 02/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 808caf2d4..5565b8022 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for `deque` objects and children in `jsonable_encoder`. PR [#9433](https://github.com/tiangolo/fastapi/pull/9433) by [@cranium](https://github.com/cranium). * ⬆ Update httpx requirement from <0.24.0,>=0.23.0 to >=0.23.0,<0.25.0. PR [#9724](https://github.com/tiangolo/fastapi/pull/9724) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump mkdocs-material from 9.1.16 to 9.1.17. PR [#9746](https://github.com/tiangolo/fastapi/pull/9746) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🔥 Remove missing translation dummy pages, no longer necessary. PR [#9751](https://github.com/tiangolo/fastapi/pull/9751) by [@tiangolo](https://github.com/tiangolo). From 0a8423d792bda91ab74c9c8b0021c9a9388cbd46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 30 Jun 2023 18:23:02 +0200 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=94=A8=20Enable=20linenums=20in=20M?= =?UTF-8?q?kDocs=20Material=20during=20local=20live=20development=20to=20s?= =?UTF-8?q?implify=20highlighting=20code=20(#9769)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/mkdocs.maybe-insiders.yml | 3 +++ docs/en/mkdocs.yml | 20 ++++++++++---------- scripts/docs.py | 2 ++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/en/mkdocs.maybe-insiders.yml b/docs/en/mkdocs.maybe-insiders.yml index 8e6271334..37fd9338e 100644 --- a/docs/en/mkdocs.maybe-insiders.yml +++ b/docs/en/mkdocs.maybe-insiders.yml @@ -1,3 +1,6 @@ # Define this here and not in the main mkdocs.yml file because that one is auto # updated and written, and the script would remove the env var INHERIT: !ENV [INSIDERS_FILE, '../en/mkdocs.no-insiders.yml'] +markdown_extensions: + pymdownx.highlight: + linenums: !ENV [LINENUMS, false] diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 21300b9dc..64dc40372 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -169,24 +169,24 @@ nav: - contributing.md - release-notes.md markdown_extensions: -- toc: + toc: permalink: true -- markdown.extensions.codehilite: + markdown.extensions.codehilite: guess_lang: false -- mdx_include: + mdx_include: base_path: docs -- admonition -- codehilite -- extra -- pymdownx.superfences: + admonition: + codehilite: + extra: + pymdownx.superfences: custom_fences: - name: mermaid class: mermaid format: !!python/name:pymdownx.superfences.fence_code_format '' -- pymdownx.tabbed: + pymdownx.tabbed: alternate_style: true -- attr_list -- md_in_html + attr_list: + md_in_html: extra: analytics: provider: google diff --git a/scripts/docs.py b/scripts/docs.py index 20838be6a..968dd9a3d 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -258,6 +258,8 @@ def live( Takes an optional LANG argument with the name of the language to serve, by default en. """ + # Enable line numbers during local development to make it easier to highlight + os.environ["LINENUMS"] = "true" if lang is None: lang = "en" lang_path: Path = docs_path / lang From 02fc9e8a63361fa25e8787d5a0da069890da62c6 Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 30 Jun 2023 16:23:36 +0000 Subject: [PATCH 04/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 5565b8022..fca7502cc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🔨 Enable linenums in MkDocs Material during local live development to simplify highlighting code. PR [#9769](https://github.com/tiangolo/fastapi/pull/9769) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for `deque` objects and children in `jsonable_encoder`. PR [#9433](https://github.com/tiangolo/fastapi/pull/9433) by [@cranium](https://github.com/cranium). * ⬆ Update httpx requirement from <0.24.0,>=0.23.0 to >=0.23.0,<0.25.0. PR [#9724](https://github.com/tiangolo/fastapi/pull/9724) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump mkdocs-material from 9.1.16 to 9.1.17. PR [#9746](https://github.com/tiangolo/fastapi/pull/9746) by [@dependabot[bot]](https://github.com/apps/dependabot). From 7dad5a820bfe99e49a6cfaefde537e09644c2c2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 30 Jun 2023 20:25:16 +0200 Subject: [PATCH 05/14] =?UTF-8?q?=E2=9C=A8=20Add=20support=20for=20OpenAPI?= =?UTF-8?q?=203.1.0=20(#9770)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Update OpenAPI models for JSON Schema 2020-12 and OpenAPI 3.1.0 * ✨ Add support for summary and webhooks * ✨ Update JSON Schema for UploadFiles * ⏪️ Revert making paths optional, to ensure always correctness * ⏪️ Keep UploadFile as format: binary for compatibility with the rest of Pydantic bytes fields in v1 * ✨ Update version of OpenAPI generated to 3.1.0 * ✨ Update the version of Swagger UI * 📝 Update docs about extending OpenAPI * 📝 Update docs and links to refer to OpenAPI 3.1.0 * ✨ Update logic for handling webhooks * ♻️ Update parameter functions and classes, deprecate example and make examples the main field * ✅ Update tests for OpenAPI 3.1.0 * 📝 Update examples for OpenAPI metadata * ✅ Add and update tests for OpenAPI metadata * 📝 Add source example for webhooks * 📝 Update docs for metadata * 📝 Update docs for Schema extra * 📝 Add docs for webhooks * 🔧 Add webhooks docs to MkDocs * ✅ Update tests for extending OpenAPI * ✅ Add tests for webhooks * ♻️ Refactor generation of OpenAPI and JSON Schema with params * 📝 Update source examples for field examples * ✅ Update tests for examples * ➕ Make sure the minimum version of typing-extensions installed has deprecated() (already a dependency of Pydantic) * ✏️ Fix typo in Webhooks example code * 🔥 Remove commented out code of removed nullable field * 🗑️ Add deprecation warnings for example argument * ✅ Update tests to check for deprecation warnings * ✅ Add test for webhooks with security schemes, for coverage * 🍱 Update image for metadata, with new summary * 🍱 Add docs image for Webhooks * 📝 Update docs for webhooks, add docs UI image --- docs/en/docs/advanced/additional-responses.md | 4 +- docs/en/docs/advanced/behind-a-proxy.md | 4 +- docs/en/docs/advanced/extending-openapi.md | 16 +- docs/en/docs/advanced/openapi-callbacks.md | 4 +- docs/en/docs/advanced/openapi-webhooks.md | 51 ++ .../path-operation-advanced-configuration.md | 2 +- .../en/docs/img/tutorial/metadata/image01.png | Bin 90062 -> 86437 bytes .../img/tutorial/openapi-webhooks/image01.png | Bin 0 -> 86925 bytes docs/en/docs/tutorial/first-steps.md | 2 +- docs/en/docs/tutorial/metadata.md | 15 +- docs/en/docs/tutorial/path-params.md | 2 +- docs/en/docs/tutorial/schema-extra-example.md | 118 ++-- docs/en/mkdocs.yml | 1 + docs_src/extending_openapi/tutorial001.py | 3 +- docs_src/metadata/tutorial001.py | 1 + docs_src/metadata/tutorial001_1.py | 38 ++ docs_src/openapi_webhooks/tutorial001.py | 25 + docs_src/schema_extra_example/tutorial001.py | 14 +- .../schema_extra_example/tutorial001_py310.py | 14 +- docs_src/schema_extra_example/tutorial002.py | 8 +- .../schema_extra_example/tutorial002_py310.py | 8 +- docs_src/schema_extra_example/tutorial003.py | 14 +- .../schema_extra_example/tutorial003_an.py | 14 +- .../tutorial003_an_py310.py | 14 +- .../tutorial003_an_py39.py | 14 +- .../schema_extra_example/tutorial003_py310.py | 14 +- docs_src/schema_extra_example/tutorial004.py | 10 +- .../schema_extra_example/tutorial004_an.py | 10 +- .../tutorial004_an_py310.py | 10 +- .../tutorial004_an_py39.py | 10 +- .../schema_extra_example/tutorial004_py310.py | 10 +- fastapi/applications.py | 8 +- fastapi/openapi/docs.py | 4 +- fastapi/openapi/models.py | 93 ++- fastapi/openapi/utils.py | 38 +- fastapi/param_functions.py | 73 ++- fastapi/params.py | 108 +++- pyproject.toml | 1 + tests/test_additional_properties.py | 2 +- tests/test_additional_response_extra.py | 2 +- tests/test_additional_responses_bad.py | 2 +- ...onal_responses_custom_model_in_callback.py | 2 +- ...tional_responses_custom_validationerror.py | 2 +- ...ional_responses_default_validationerror.py | 2 +- ...est_additional_responses_response_class.py | 2 +- tests/test_additional_responses_router.py | 2 +- tests/test_annotated.py | 2 +- tests/test_application.py | 2 +- tests/test_custom_route_class.py | 2 +- tests/test_dependency_duplicates.py | 2 +- tests/test_deprecated_openapi_prefix.py | 2 +- tests/test_duplicate_models_openapi.py | 2 +- tests/test_enforce_once_required_parameter.py | 2 +- tests/test_extra_routes.py | 2 +- tests/test_filter_pydantic_sub_model.py | 2 +- tests/test_generate_unique_id_function.py | 14 +- tests/test_get_request_body.py | 2 +- .../test_include_router_defaults_overrides.py | 2 +- .../test_modules_same_name_body/test_main.py | 2 +- tests/test_multi_body_errors.py | 2 +- tests/test_multi_query_errors.py | 2 +- .../test_openapi_query_parameter_extension.py | 2 +- tests/test_openapi_route_extensions.py | 2 +- tests/test_openapi_servers.py | 2 +- tests/test_param_in_path_and_dependency.py | 2 +- tests/test_param_include_in_schema.py | 2 +- tests/test_put_no_body.py | 2 +- tests/test_repeated_dependency_schema.py | 2 +- tests/test_repeated_parameter_alias.py | 2 +- tests/test_reponse_set_reponse_code_empty.py | 2 +- ...test_request_body_parameters_media_type.py | 2 +- tests/test_response_by_alias.py | 2 +- tests/test_response_class_no_mediatype.py | 2 +- tests/test_response_code_no_body.py | 2 +- ...est_response_model_as_return_annotation.py | 2 +- tests/test_response_model_sub_types.py | 2 +- tests/test_schema_extra_examples.py | 572 ++++++++---------- tests/test_security_api_key_cookie.py | 2 +- ...est_security_api_key_cookie_description.py | 2 +- .../test_security_api_key_cookie_optional.py | 2 +- tests/test_security_api_key_header.py | 2 +- ...est_security_api_key_header_description.py | 2 +- .../test_security_api_key_header_optional.py | 2 +- tests/test_security_api_key_query.py | 2 +- ...test_security_api_key_query_description.py | 2 +- tests/test_security_api_key_query_optional.py | 2 +- tests/test_security_http_base.py | 2 +- tests/test_security_http_base_description.py | 2 +- tests/test_security_http_base_optional.py | 2 +- tests/test_security_http_basic_optional.py | 2 +- tests/test_security_http_basic_realm.py | 2 +- ...t_security_http_basic_realm_description.py | 2 +- tests/test_security_http_bearer.py | 2 +- .../test_security_http_bearer_description.py | 2 +- tests/test_security_http_bearer_optional.py | 2 +- tests/test_security_http_digest.py | 2 +- .../test_security_http_digest_description.py | 2 +- tests/test_security_http_digest_optional.py | 2 +- tests/test_security_oauth2.py | 2 +- ...curity_oauth2_authorization_code_bearer.py | 2 +- ...2_authorization_code_bearer_description.py | 2 +- tests/test_security_oauth2_optional.py | 2 +- ...st_security_oauth2_optional_description.py | 2 +- ...ecurity_oauth2_password_bearer_optional.py | 2 +- ...h2_password_bearer_optional_description.py | 2 +- tests/test_security_openid_connect.py | 2 +- ...est_security_openid_connect_description.py | 2 +- .../test_security_openid_connect_optional.py | 2 +- tests/test_starlette_exception.py | 2 +- tests/test_sub_callbacks.py | 2 +- tests/test_tuples.py | 2 +- .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 2 +- .../test_tutorial003.py | 2 +- .../test_tutorial004.py | 2 +- .../test_tutorial001.py | 2 +- .../test_behind_a_proxy/test_tutorial001.py | 2 +- .../test_behind_a_proxy/test_tutorial002.py | 2 +- .../test_behind_a_proxy/test_tutorial003.py | 2 +- .../test_behind_a_proxy/test_tutorial004.py | 2 +- .../test_bigger_applications/test_main.py | 2 +- .../test_bigger_applications/test_main_an.py | 2 +- .../test_main_an_py39.py | 2 +- .../test_body/test_tutorial001.py | 2 +- .../test_body/test_tutorial001_py310.py | 2 +- .../test_body_fields/test_tutorial001.py | 2 +- .../test_body_fields/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial001.py | 2 +- .../test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial003.py | 2 +- .../test_tutorial003_an.py | 2 +- .../test_tutorial003_an_py310.py | 2 +- .../test_tutorial003_an_py39.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_tutorial009.py | 2 +- .../test_tutorial009_py39.py | 2 +- .../test_body_updates/test_tutorial001.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_tutorial001_py39.py | 2 +- .../test_tutorial001.py | 2 +- .../test_cookie_params/test_tutorial001.py | 2 +- .../test_cookie_params/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_custom_response/test_tutorial001.py | 2 +- .../test_custom_response/test_tutorial001b.py | 2 +- .../test_custom_response/test_tutorial004.py | 2 +- .../test_custom_response/test_tutorial005.py | 2 +- .../test_custom_response/test_tutorial006.py | 2 +- .../test_custom_response/test_tutorial006b.py | 2 +- .../test_custom_response/test_tutorial006c.py | 2 +- .../test_dataclasses/test_tutorial001.py | 2 +- .../test_dataclasses/test_tutorial002.py | 2 +- .../test_dataclasses/test_tutorial003.py | 2 +- .../test_dependencies/test_tutorial001.py | 2 +- .../test_dependencies/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_dependencies/test_tutorial004.py | 2 +- .../test_dependencies/test_tutorial004_an.py | 2 +- .../test_tutorial004_an_py310.py | 2 +- .../test_tutorial004_an_py39.py | 2 +- .../test_tutorial004_py310.py | 2 +- .../test_dependencies/test_tutorial006.py | 2 +- .../test_dependencies/test_tutorial006_an.py | 2 +- .../test_tutorial006_an_py39.py | 2 +- .../test_dependencies/test_tutorial012.py | 2 +- .../test_dependencies/test_tutorial012_an.py | 2 +- .../test_tutorial012_an_py39.py | 2 +- .../test_events/test_tutorial001.py | 2 +- .../test_events/test_tutorial002.py | 2 +- .../test_events/test_tutorial003.py | 2 +- .../test_tutorial001.py | 5 +- .../test_extra_data_types/test_tutorial001.py | 2 +- .../test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_extra_models/test_tutorial003.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_extra_models/test_tutorial004.py | 2 +- .../test_tutorial004_py39.py | 2 +- .../test_extra_models/test_tutorial005.py | 2 +- .../test_tutorial005_py39.py | 2 +- .../test_first_steps/test_tutorial001.py | 2 +- .../test_generate_clients/test_tutorial003.py | 2 +- .../test_handling_errors/test_tutorial001.py | 2 +- .../test_handling_errors/test_tutorial002.py | 2 +- .../test_handling_errors/test_tutorial003.py | 2 +- .../test_handling_errors/test_tutorial004.py | 2 +- .../test_handling_errors/test_tutorial005.py | 2 +- .../test_handling_errors/test_tutorial006.py | 2 +- .../test_header_params/test_tutorial001.py | 2 +- .../test_header_params/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py310.py | 2 +- .../test_tutorial001_py310.py | 2 +- .../test_header_params/test_tutorial002.py | 2 +- .../test_header_params/test_tutorial002_an.py | 2 +- .../test_tutorial002_an_py310.py | 2 +- .../test_tutorial002_an_py39.py | 2 +- .../test_tutorial002_py310.py | 2 +- .../test_header_params/test_tutorial003.py | 2 +- .../test_header_params/test_tutorial003_an.py | 2 +- .../test_tutorial003_an_py310.py | 2 +- .../test_tutorial003_an_py39.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_metadata/test_tutorial001.py | 3 +- .../test_metadata/test_tutorial001_1.py | 49 ++ .../test_metadata/test_tutorial004.py | 2 +- .../test_tutorial001.py | 2 +- .../test_openapi_webhooks/__init__.py | 0 .../test_openapi_webhooks/test_tutorial001.py | 117 ++++ .../test_tutorial001.py | 2 +- .../test_tutorial002.py | 2 +- .../test_tutorial003.py | 2 +- .../test_tutorial004.py | 2 +- .../test_tutorial005.py | 2 +- .../test_tutorial006.py | 2 +- .../test_tutorial007.py | 2 +- .../test_tutorial002b.py | 2 +- .../test_tutorial005.py | 2 +- .../test_tutorial005_py310.py | 2 +- .../test_tutorial005_py39.py | 2 +- .../test_tutorial006.py | 2 +- .../test_path_params/test_tutorial004.py | 2 +- .../test_path_params/test_tutorial005.py | 2 +- .../test_query_params/test_tutorial005.py | 2 +- .../test_query_params/test_tutorial006.py | 2 +- .../test_tutorial006_py310.py | 2 +- .../test_tutorial010.py | 2 +- .../test_tutorial010_an.py | 2 +- .../test_tutorial010_an_py310.py | 2 +- .../test_tutorial010_an_py39.py | 2 +- .../test_tutorial010_py310.py | 2 +- .../test_tutorial011.py | 2 +- .../test_tutorial011_an.py | 2 +- .../test_tutorial011_an_py310.py | 2 +- .../test_tutorial011_an_py39.py | 2 +- .../test_tutorial011_py310.py | 2 +- .../test_tutorial011_py39.py | 2 +- .../test_tutorial012.py | 2 +- .../test_tutorial012_an.py | 2 +- .../test_tutorial012_an_py39.py | 2 +- .../test_tutorial012_py39.py | 2 +- .../test_tutorial013.py | 2 +- .../test_tutorial013_an.py | 2 +- .../test_tutorial013_an_py39.py | 2 +- .../test_tutorial014.py | 2 +- .../test_tutorial014_an.py | 2 +- .../test_tutorial014_an_py310.py | 2 +- .../test_tutorial014_an_py39.py | 2 +- .../test_tutorial014_py310.py | 2 +- .../test_request_files/test_tutorial001.py | 2 +- .../test_request_files/test_tutorial001_02.py | 2 +- .../test_tutorial001_02_an.py | 2 +- .../test_tutorial001_02_an_py310.py | 2 +- .../test_tutorial001_02_an_py39.py | 2 +- .../test_tutorial001_02_py310.py | 2 +- .../test_request_files/test_tutorial001_03.py | 2 +- .../test_tutorial001_03_an.py | 2 +- .../test_tutorial001_03_an_py39.py | 2 +- .../test_request_files/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_request_files/test_tutorial002.py | 2 +- .../test_request_files/test_tutorial002_an.py | 2 +- .../test_tutorial002_an_py39.py | 2 +- .../test_tutorial002_py39.py | 2 +- .../test_request_files/test_tutorial003.py | 2 +- .../test_request_files/test_tutorial003_an.py | 2 +- .../test_tutorial003_an_py39.py | 2 +- .../test_tutorial003_py39.py | 2 +- .../test_request_forms/test_tutorial001.py | 2 +- .../test_request_forms/test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_tutorial001.py | 2 +- .../test_tutorial001_an.py | 2 +- .../test_tutorial001_an_py39.py | 2 +- .../test_response_model/test_tutorial003.py | 2 +- .../test_tutorial003_01.py | 2 +- .../test_tutorial003_01_py310.py | 2 +- .../test_tutorial003_02.py | 2 +- .../test_tutorial003_03.py | 2 +- .../test_tutorial003_05.py | 2 +- .../test_tutorial003_05_py310.py | 2 +- .../test_tutorial003_py310.py | 2 +- .../test_response_model/test_tutorial004.py | 2 +- .../test_tutorial004_py310.py | 2 +- .../test_tutorial004_py39.py | 2 +- .../test_response_model/test_tutorial005.py | 2 +- .../test_tutorial005_py310.py | 2 +- .../test_response_model/test_tutorial006.py | 2 +- .../test_tutorial006_py310.py | 2 +- .../test_tutorial004.py | 51 +- .../test_tutorial004_an.py | 51 +- .../test_tutorial004_an_py310.py | 51 +- .../test_tutorial004_an_py39.py | 51 +- .../test_tutorial004_py310.py | 51 +- .../test_security/test_tutorial001.py | 2 +- .../test_security/test_tutorial001_an.py | 2 +- .../test_security/test_tutorial001_an_py39.py | 2 +- .../test_security/test_tutorial003.py | 2 +- .../test_security/test_tutorial003_an.py | 2 +- .../test_tutorial003_an_py310.py | 2 +- .../test_security/test_tutorial003_an_py39.py | 2 +- .../test_security/test_tutorial003_py310.py | 2 +- .../test_security/test_tutorial005.py | 2 +- .../test_security/test_tutorial005_an.py | 2 +- .../test_tutorial005_an_py310.py | 2 +- .../test_security/test_tutorial005_an_py39.py | 2 +- .../test_security/test_tutorial005_py310.py | 2 +- .../test_security/test_tutorial005_py39.py | 2 +- .../test_security/test_tutorial006.py | 2 +- .../test_security/test_tutorial006_an.py | 2 +- .../test_security/test_tutorial006_an_py39.py | 2 +- .../test_sql_databases/test_sql_databases.py | 2 +- .../test_sql_databases_middleware.py | 2 +- .../test_sql_databases_middleware_py310.py | 2 +- .../test_sql_databases_middleware_py39.py | 2 +- .../test_sql_databases_py310.py | 2 +- .../test_sql_databases_py39.py | 2 +- .../test_sql_databases_peewee.py | 2 +- .../test_sub_applications/test_tutorial001.py | 4 +- tests/test_tutorial/test_testing/test_main.py | 2 +- .../test_testing/test_tutorial001.py | 2 +- tests/test_union_body.py | 2 +- tests/test_union_inherited_body.py | 2 +- tests/test_webhooks_security.py | 126 ++++ 335 files changed, 1564 insertions(+), 922 deletions(-) create mode 100644 docs/en/docs/advanced/openapi-webhooks.md create mode 100644 docs/en/docs/img/tutorial/openapi-webhooks/image01.png create mode 100644 docs_src/metadata/tutorial001_1.py create mode 100644 docs_src/openapi_webhooks/tutorial001.py create mode 100644 tests/test_tutorial/test_metadata/test_tutorial001_1.py create mode 100644 tests/test_tutorial/test_openapi_webhooks/__init__.py create mode 100644 tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py create mode 100644 tests/test_webhooks_security.py diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md index dca5f6a98..624036ce9 100644 --- a/docs/en/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -236,5 +236,5 @@ For example: To see what exactly you can include in the responses, you can check these sections in the OpenAPI specification: -* OpenAPI Responses Object, it includes the `Response Object`. -* OpenAPI Response Object, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`. +* OpenAPI Responses Object, it includes the `Response Object`. +* OpenAPI Response Object, you can include anything from this directly in each response inside your `responses` parameter. Including `description`, `headers`, `content` (inside of this is that you declare different media types and JSON Schemas), and `links`. diff --git a/docs/en/docs/advanced/behind-a-proxy.md b/docs/en/docs/advanced/behind-a-proxy.md index 03198851a..e7af77f3d 100644 --- a/docs/en/docs/advanced/behind-a-proxy.md +++ b/docs/en/docs/advanced/behind-a-proxy.md @@ -46,7 +46,7 @@ The docs UI would also need the OpenAPI schema to declare that this API `server` ```JSON hl_lines="4-8" { - "openapi": "3.0.2", + "openapi": "3.1.0", // More stuff here "servers": [ { @@ -298,7 +298,7 @@ Will generate an OpenAPI schema like: ```JSON hl_lines="5-7" { - "openapi": "3.0.2", + "openapi": "3.1.0", // More stuff here "servers": [ { diff --git a/docs/en/docs/advanced/extending-openapi.md b/docs/en/docs/advanced/extending-openapi.md index 36619696b..c47f939af 100644 --- a/docs/en/docs/advanced/extending-openapi.md +++ b/docs/en/docs/advanced/extending-openapi.md @@ -29,10 +29,14 @@ And that function `get_openapi()` receives as parameters: * `title`: The OpenAPI title, shown in the docs. * `version`: The version of your API, e.g. `2.5.0`. -* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.0.2`. -* `description`: The description of your API. +* `openapi_version`: The version of the OpenAPI specification used. By default, the latest: `3.1.0`. +* `summary`: A short summary of the API. +* `description`: The description of your API, this can include markdown and will be shown in the docs. * `routes`: A list of routes, these are each of the registered *path operations*. They are taken from `app.routes`. +!!! info + The parameter `summary` is available in OpenAPI 3.1.0 and above, supported by FastAPI 0.99.0 and above. + ## Overriding the defaults Using the information above, you can use the same utility function to generate the OpenAPI schema and override each part that you need. @@ -51,7 +55,7 @@ First, write all your **FastAPI** application as normally: Then, use the same utility function to generate the OpenAPI schema, inside a `custom_openapi()` function: -```Python hl_lines="2 15-20" +```Python hl_lines="2 15-21" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` @@ -59,7 +63,7 @@ Then, use the same utility function to generate the OpenAPI schema, inside a `cu Now you can add the ReDoc extension, adding a custom `x-logo` to the `info` "object" in the OpenAPI schema: -```Python hl_lines="21-23" +```Python hl_lines="22-24" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` @@ -71,7 +75,7 @@ That way, your application won't have to generate the schema every time a user o It will be generated only once, and then the same cached schema will be used for the next requests. -```Python hl_lines="13-14 24-25" +```Python hl_lines="13-14 25-26" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` @@ -79,7 +83,7 @@ It will be generated only once, and then the same cached schema will be used for Now you can replace the `.openapi()` method with your new function. -```Python hl_lines="28" +```Python hl_lines="29" {!../../../docs_src/extending_openapi/tutorial001.py!} ``` diff --git a/docs/en/docs/advanced/openapi-callbacks.md b/docs/en/docs/advanced/openapi-callbacks.md index 71924ce8b..37339eae5 100644 --- a/docs/en/docs/advanced/openapi-callbacks.md +++ b/docs/en/docs/advanced/openapi-callbacks.md @@ -103,11 +103,11 @@ It should look just like a normal FastAPI *path operation*: There are 2 main differences from a normal *path operation*: * It doesn't need to have any actual code, because your app will never call this code. It's only used to document the *external API*. So, the function could just have `pass`. -* The *path* can contain an OpenAPI 3 expression (see more below) where it can use variables with parameters and parts of the original request sent to *your API*. +* The *path* can contain an OpenAPI 3 expression (see more below) where it can use variables with parameters and parts of the original request sent to *your API*. ### The callback path expression -The callback *path* can have an OpenAPI 3 expression that can contain parts of the original request sent to *your API*. +The callback *path* can have an OpenAPI 3 expression that can contain parts of the original request sent to *your API*. In this case, it's the `str`: diff --git a/docs/en/docs/advanced/openapi-webhooks.md b/docs/en/docs/advanced/openapi-webhooks.md new file mode 100644 index 000000000..63cbdc610 --- /dev/null +++ b/docs/en/docs/advanced/openapi-webhooks.md @@ -0,0 +1,51 @@ +# OpenAPI Webhooks + +There are cases where you want to tell your API **users** that your app could call *their* app (sending a request) with some data, normally to **notify** of some type of **event**. + +This means that instead of the normal process of your users sending requests to your API, it's **your API** (or your app) that could **send requests to their system** (to their API, their app). + +This is normally called a **webhook**. + +## Webhooks steps + +The process normally is that **you define** in your code what is the message that you will send, the **body of the request**. + +You also define in some way at which **moments** your app will send those requests or events. + +And **your users** define in some way (for example in a web dashboard somewhere) the **URL** where your app should send those requests. + +All the **logic** about how to register the URLs for webhooks and the code to actually send those requests is up to you. You write it however you want to in **your own code**. + +## Documenting webhooks with **FastAPI** and OpenAPI + +With **FastAPI**, using OpenAPI, you can define the names of these webhooks, the types of HTTP operations that your app can send (e.g. `POST`, `PUT`, etc.) and the request **bodies** that your app would send. + +This can make it a lot easier for your users to **implement their APIs** to receive your **webhook** requests, they might even be able to autogenerate some of their own API code. + +!!! info + Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` and above. + +## An app with webhooks + +When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`. + +```Python hl_lines="9-13 36-53" +{!../../../docs_src/openapi_webhooks/tutorial001.py!} +``` + +The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. + +!!! info + The `app.webhooks` object is actually just an `APIRouter`, the same type you would use when structuring your app with multiple files. + +Notice that with webhooks you are actually not declaring a *path* (like `/items/`), the text you pass there is just an **identifier** of the webhook (the name of the event), for example in `@app.webhooks.post("new-subscription")`, the webhook name is `new-subscription`. + +This is because it is expected that **your users** would define the actual **URL path** where they want to receive the webhook request in some other way (e.g. a web dashboard). + +### Check the docs + +Now you can start your app with Uvicorn and go to http://127.0.0.1:8000/docs. + +You will see your docs have the normal *path operations* and now also some **webhooks**: + + diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index a1c902ef2..6d9a5fe70 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -97,7 +97,7 @@ And if you see the resulting OpenAPI (at `/openapi.json` in your API), you will ```JSON hl_lines="22" { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "FastAPI", "version": "0.1.0" diff --git a/docs/en/docs/img/tutorial/metadata/image01.png b/docs/en/docs/img/tutorial/metadata/image01.png index b7708a3fd98ad2170d880781896623ec8ed80204..4146a8607b5b4278b9d826c5d9e45ee9ff183ce3 100644 GIT binary patch literal 86437 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 literal 90062 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 diff --git a/docs/en/docs/img/tutorial/openapi-webhooks/image01.png b/docs/en/docs/img/tutorial/openapi-webhooks/image01.png new file mode 100644 index 0000000000000000000000000000000000000000..25ced48186d8395b0406b9a66e75afb17aa83fd5 GIT binary patch literal 86925 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�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 literal 0 HcmV?d00001 diff --git a/docs/en/docs/tutorial/first-steps.md b/docs/en/docs/tutorial/first-steps.md index 6ca5f39eb..cfa159329 100644 --- a/docs/en/docs/tutorial/first-steps.md +++ b/docs/en/docs/tutorial/first-steps.md @@ -99,7 +99,7 @@ It will show a JSON starting with something like: ```JSON { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "FastAPI", "version": "0.1.0" diff --git a/docs/en/docs/tutorial/metadata.md b/docs/en/docs/tutorial/metadata.md index cf13e7470..e75b4a0b9 100644 --- a/docs/en/docs/tutorial/metadata.md +++ b/docs/en/docs/tutorial/metadata.md @@ -9,15 +9,16 @@ You can set the following fields that are used in the OpenAPI specification and | Parameter | Type | Description | |------------|------|-------------| | `title` | `str` | The title of the API. | +| `summary` | `str` | A short summary of the API. Available since OpenAPI 3.1.0, FastAPI 0.99.0. | | `description` | `str` | A short description of the API. It can use Markdown. | | `version` | `string` | The version of the API. This is the version of your own application, not of OpenAPI. For example `2.5.0`. | | `terms_of_service` | `str` | A URL to the Terms of Service for the API. If provided, this has to be a URL. | | `contact` | `dict` | The contact information for the exposed API. It can contain several fields.
contact fields
ParameterTypeDescription
namestrThe identifying name of the contact person/organization.
urlstrThe URL pointing to the contact information. MUST be in the format of a URL.
emailstrThe email address of the contact person/organization. MUST be in the format of an email address.
| -| `license_info` | `dict` | The license information for the exposed API. It can contain several fields.
license_info fields
ParameterTypeDescription
namestrREQUIRED (if a license_info is set). The license name used for the API.
urlstrA URL to the license used for the API. MUST be in the format of a URL.
| +| `license_info` | `dict` | The license information for the exposed API. It can contain several fields.
license_info fields
ParameterTypeDescription
namestrREQUIRED (if a license_info is set). The license name used for the API.
identifierstrAn SPDX license expression for the API. The identifier field is mutually exclusive of the url field. Available since OpenAPI 3.1.0, FastAPI 0.99.0.
urlstrA URL to the license used for the API. MUST be in the format of a URL.
| You can set them as follows: -```Python hl_lines="3-16 19-31" +```Python hl_lines="3-16 19-32" {!../../../docs_src/metadata/tutorial001.py!} ``` @@ -28,6 +29,16 @@ With this configuration, the automatic API docs would look like: +## License identifier + +Since OpenAPI 3.1.0 and FastAPI 0.99.0, you can also set the `license_info` with an `identifier` instead of a `url`. + +For example: + +```Python hl_lines="31" +{!../../../docs_src/metadata/tutorial001_1.py!} +``` + ## Metadata for tags You can also add additional metadata for the different tags used to group your path operations with the parameter `openapi_tags`. diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md index a0d70692e..6594a7a8b 100644 --- a/docs/en/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -83,7 +83,7 @@ And when you open your browser at
OpenAPI standard, there are many compatible tools. +And because the generated schema is from the OpenAPI standard, there are many compatible tools. Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc), which you can access at http://127.0.0.1:8000/redoc: diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index e0f7ed256..6cf8bf181 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -6,17 +6,17 @@ Here are several ways to do it. ## Pydantic `schema_extra` -You can declare an `example` for a Pydantic model using `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization: +You can declare `examples` for a Pydantic model using `Config` and `schema_extra`, as described in Pydantic's docs: Schema customization: === "Python 3.10+" - ```Python hl_lines="13-21" + ```Python hl_lines="13-23" {!> ../../../docs_src/schema_extra_example/tutorial001_py310.py!} ``` === "Python 3.6+" - ```Python hl_lines="15-23" + ```Python hl_lines="15-25" {!> ../../../docs_src/schema_extra_example/tutorial001.py!} ``` @@ -27,11 +27,16 @@ That extra info will be added as-is to the output **JSON Schema** for that model For example you could use it to add metadata for a frontend user interface, etc. -## `Field` additional arguments +!!! info + OpenAPI 3.1.0 (used since FastAPI 0.99.0) added support for `examples`, which is part of the **JSON Schema** standard. + + Before that, it only supported the keyword `example` with a single example. That is still supported by OpenAPI 3.1.0, but is deprecated and is not part of the JSON Schema standard. So you are encouraged to migrate `example` to `examples`. 🤓 + + You can read more at the end of this page. -When using `Field()` with Pydantic models, you can also declare extra info for the **JSON Schema** by passing any other arbitrary arguments to the function. +## `Field` additional arguments -You can use this to add `example` for each field: +When using `Field()` with Pydantic models, you can also declare additional `examples`: === "Python 3.10+" @@ -45,10 +50,7 @@ You can use this to add `example` for each field: {!> ../../../docs_src/schema_extra_example/tutorial002.py!} ``` -!!! warning - Keep in mind that those extra arguments passed won't add any validation, only extra information, for documentation purposes. - -## `example` and `examples` in OpenAPI +## `examples` in OpenAPI When using any of: @@ -60,27 +62,27 @@ When using any of: * `Form()` * `File()` -you can also declare a data `example` or a group of `examples` with additional information that will be added to **OpenAPI**. +you can also declare a group of `examples` with additional information that will be added to **OpenAPI**. -### `Body` with `example` +### `Body` with `examples` -Here we pass an `example` of the data expected in `Body()`: +Here we pass `examples` containing one example of the data expected in `Body()`: === "Python 3.10+" - ```Python hl_lines="22-27" + ```Python hl_lines="22-29" {!> ../../../docs_src/schema_extra_example/tutorial003_an_py310.py!} ``` === "Python 3.9+" - ```Python hl_lines="22-27" + ```Python hl_lines="22-29" {!> ../../../docs_src/schema_extra_example/tutorial003_an_py39.py!} ``` === "Python 3.6+" - ```Python hl_lines="23-28" + ```Python hl_lines="23-30" {!> ../../../docs_src/schema_extra_example/tutorial003_an.py!} ``` @@ -89,7 +91,7 @@ Here we pass an `example` of the data expected in `Body()`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="18-23" + ```Python hl_lines="18-25" {!> ../../../docs_src/schema_extra_example/tutorial003_py310.py!} ``` @@ -98,7 +100,7 @@ Here we pass an `example` of the data expected in `Body()`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="20-25" + ```Python hl_lines="20-27" {!> ../../../docs_src/schema_extra_example/tutorial003.py!} ``` @@ -110,16 +112,7 @@ With any of the methods above it would look like this in the `/docs`: ### `Body` with multiple `examples` -Alternatively to the single `example`, you can pass `examples` using a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too. - -The keys of the `dict` identify each example, and each value is another `dict`. - -Each specific example `dict` in the `examples` can contain: - -* `summary`: Short description for the example. -* `description`: A long description that can contain Markdown text. -* `value`: This is the actual example shown, e.g. a `dict`. -* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. +You can of course also pass multiple `examples`: === "Python 3.10+" @@ -165,25 +158,76 @@ With `examples` added to `Body()` the `/docs` would look like: ## Technical Details +!!! tip + If you are already using **FastAPI** version **0.99.0 or above**, you can probably **skip** these details. + + They are more relevant for older versions, before OpenAPI 3.1.0 was available. + + You can consider this a brief OpenAPI and JSON Schema **history lesson**. 🤓 + !!! warning These are very technical details about the standards **JSON Schema** and **OpenAPI**. If the ideas above already work for you, that might be enough, and you probably don't need these details, feel free to skip them. -When you add an example inside of a Pydantic model, using `schema_extra` or `Field(example="something")` that example is added to the **JSON Schema** for that Pydantic model. +Before OpenAPI 3.1.0, OpenAPI used an older and modified version of **JSON Schema**. -And that **JSON Schema** of the Pydantic model is included in the **OpenAPI** of your API, and then it's used in the docs UI. +JSON Schema didn't have `examples`, so OpenAPI added it's own `example` field to its own modified version. + +OpenAPI also added `example` and `examples` fields to other parts of the specification: + +* `Parameter Object` (in the specification) that was used by FastAPI's: + * `Path()` + * `Query()` + * `Header()` + * `Cookie()` +* `Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification) that was used by FastAPI's: + * `Body()` + * `File()` + * `Form()` -**JSON Schema** doesn't really have a field `example` in the standards. Recent versions of JSON Schema define a field `examples`, but OpenAPI 3.0.3 is based on an older version of JSON Schema that didn't have `examples`. +### OpenAPI's `examples` field -So, OpenAPI 3.0.3 defined its own `example` for the modified version of **JSON Schema** it uses, for the same purpose (but it's a single `example`, not `examples`), and that's what is used by the API docs UI (using Swagger UI). +The shape of this field `examples` from OpenAPI is a `dict` with **multiple examples**, each with extra information that will be added to **OpenAPI** too. + +The keys of the `dict` identify each example, and each value is another `dict`. + +Each specific example `dict` in the `examples` can contain: + +* `summary`: Short description for the example. +* `description`: A long description that can contain Markdown text. +* `value`: This is the actual example shown, e.g. a `dict`. +* `externalValue`: alternative to `value`, a URL pointing to the example. Although this might not be supported by as many tools as `value`. + +This applies to those other parts of the OpenAPI specification apart from JSON Schema. + +### JSON Schema's `examples` field + +But then JSON Schema added an `examples` field to a new version of the specification. + +And then the new OpenAPI 3.1.0 was based on the latest version (JSON Schema 2020-12) that included this new field `examples`. + +And now this new `examples` field takes precedence over the old single (and custom) `example` field, that is now deprecated. + +This new `examples` field in JSON Schema is **just a `list`** of examples, not a dict with extra metadata as in the other places in OpenAPI (described above). + +!!! info + Even after OpenAPI 3.1.0 was released with this new simpler integration with JSON Schema, for a while, Swagger UI, the tool that provides the automatic docs, didn't support OpenAPI 3.1.0 (it does since version 5.0.0 🎉). + + Because of that, versions of FastAPI previous to 0.99.0 still used versions of OpenAPI lower than 3.1.0. + +### Pydantic and FastAPI `examples` + +When you add `examples` inside of a Pydantic model, using `schema_extra` or `Field(examples=["something"])` that example is added to the **JSON Schema** for that Pydantic model. + +And that **JSON Schema** of the Pydantic model is included in the **OpenAPI** of your API, and then it's used in the docs UI. -So, although `example` is not part of JSON Schema, it is part of OpenAPI's custom version of JSON Schema, and that's what will be used by the docs UI. +In versions of FastAPI before 0.99.0 (0.99.0 and above use the newer OpenAPI 3.1.0) when you used `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples were not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they were added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema). -But when you use `example` or `examples` with any of the other utilities (`Query()`, `Body()`, etc.) those examples are not added to the JSON Schema that describes that data (not even to OpenAPI's own version of JSON Schema), they are added directly to the *path operation* declaration in OpenAPI (outside the parts of OpenAPI that use JSON Schema). +But now that FastAPI 0.99.0 and above uses OpenAPI 3.1.0, that uses JSON Schema 2020-12, and Swagger UI 5.0.0 and above, everything is more consistent and the examples are included in JSON Schema. -For `Path()`, `Query()`, `Header()`, and `Cookie()`, the `example` or `examples` are added to the OpenAPI definition, to the `Parameter Object` (in the specification). +### Summary -And for `Body()`, `File()`, and `Form()`, the `example` or `examples` are equivalently added to the OpenAPI definition, to the `Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification). +I used to say I didn't like history that much... and look at me now giving "tech history" lessons. 😅 -On the other hand, there's a newer version of OpenAPI: **3.1.0**, recently released. It is based on the latest JSON Schema and most of the modifications from OpenAPI's custom version of JSON Schema are removed, in exchange of the features from the recent versions of JSON Schema, so all these small differences are reduced. Nevertheless, Swagger UI currently doesn't support OpenAPI 3.1.0, so, for now, it's better to continue using the ideas above. +In short, **upgrade to FastAPI 0.99.0 or above**, and things are much **simpler, consistent, and intuitive**, and you don't have to know all these historic details. 😎 diff --git a/docs/en/mkdocs.yml b/docs/en/mkdocs.yml index 64dc40372..030bbe5d3 100644 --- a/docs/en/mkdocs.yml +++ b/docs/en/mkdocs.yml @@ -147,6 +147,7 @@ nav: - advanced/conditional-openapi.md - advanced/extending-openapi.md - advanced/openapi-callbacks.md + - advanced/openapi-webhooks.md - advanced/wsgi.md - advanced/generate-clients.md - async.md diff --git a/docs_src/extending_openapi/tutorial001.py b/docs_src/extending_openapi/tutorial001.py index 561e95898..35e31c0e0 100644 --- a/docs_src/extending_openapi/tutorial001.py +++ b/docs_src/extending_openapi/tutorial001.py @@ -15,7 +15,8 @@ def custom_openapi(): openapi_schema = get_openapi( title="Custom title", version="2.5.0", - description="This is a very custom OpenAPI schema", + summary="This is a very custom OpenAPI schema", + description="Here's a longer description of the custom **OpenAPI** schema", routes=app.routes, ) openapi_schema["info"]["x-logo"] = { diff --git a/docs_src/metadata/tutorial001.py b/docs_src/metadata/tutorial001.py index 3fba9e7d1..76656e81b 100644 --- a/docs_src/metadata/tutorial001.py +++ b/docs_src/metadata/tutorial001.py @@ -18,6 +18,7 @@ You will be able to: app = FastAPI( title="ChimichangApp", description=description, + summary="Deadpool's favorite app. Nuff said.", version="0.0.1", terms_of_service="http://example.com/terms/", contact={ diff --git a/docs_src/metadata/tutorial001_1.py b/docs_src/metadata/tutorial001_1.py new file mode 100644 index 000000000..a8f5b9458 --- /dev/null +++ b/docs_src/metadata/tutorial001_1.py @@ -0,0 +1,38 @@ +from fastapi import FastAPI + +description = """ +ChimichangApp API helps you do awesome stuff. 🚀 + +## Items + +You can **read items**. + +## Users + +You will be able to: + +* **Create users** (_not implemented_). +* **Read users** (_not implemented_). +""" + +app = FastAPI( + title="ChimichangApp", + description=description, + summary="Deadpool's favorite app. Nuff said.", + version="0.0.1", + terms_of_service="http://example.com/terms/", + contact={ + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + license_info={ + "name": "Apache 2.0", + "identifier": "MIT", + }, +) + + +@app.get("/items/") +async def read_items(): + return [{"name": "Katana"}] diff --git a/docs_src/openapi_webhooks/tutorial001.py b/docs_src/openapi_webhooks/tutorial001.py new file mode 100644 index 000000000..5016f5b00 --- /dev/null +++ b/docs_src/openapi_webhooks/tutorial001.py @@ -0,0 +1,25 @@ +from datetime import datetime + +from fastapi import FastAPI +from pydantic import BaseModel + +app = FastAPI() + + +class Subscription(BaseModel): + username: str + montly_fee: float + start_date: datetime + + +@app.webhooks.post("new-subscription") +def new_subscription(body: Subscription): + """ + When a new user subscribes to your service we'll send you a POST request with this + data to the URL that you register for the event `new-subscription` in the dashboard. + """ + + +@app.get("/users/") +def read_users(): + return ["Rick", "Morty"] diff --git a/docs_src/schema_extra_example/tutorial001.py b/docs_src/schema_extra_example/tutorial001.py index a5ae28127..6ab96ff85 100644 --- a/docs_src/schema_extra_example/tutorial001.py +++ b/docs_src/schema_extra_example/tutorial001.py @@ -14,12 +14,14 @@ class Item(BaseModel): class Config: schema_extra = { - "example": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } + "examples": [ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ] } diff --git a/docs_src/schema_extra_example/tutorial001_py310.py b/docs_src/schema_extra_example/tutorial001_py310.py index 77ceedd60..ec83f1112 100644 --- a/docs_src/schema_extra_example/tutorial001_py310.py +++ b/docs_src/schema_extra_example/tutorial001_py310.py @@ -12,12 +12,14 @@ class Item(BaseModel): class Config: schema_extra = { - "example": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } + "examples": [ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ] } diff --git a/docs_src/schema_extra_example/tutorial002.py b/docs_src/schema_extra_example/tutorial002.py index 6de434f81..70f06567c 100644 --- a/docs_src/schema_extra_example/tutorial002.py +++ b/docs_src/schema_extra_example/tutorial002.py @@ -7,10 +7,10 @@ app = FastAPI() class Item(BaseModel): - name: str = Field(example="Foo") - description: Union[str, None] = Field(default=None, example="A very nice Item") - price: float = Field(example=35.4) - tax: Union[float, None] = Field(default=None, example=3.2) + name: str = Field(examples=["Foo"]) + description: Union[str, None] = Field(default=None, examples=["A very nice Item"]) + price: float = Field(examples=[35.4]) + tax: Union[float, None] = Field(default=None, examples=[3.2]) @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial002_py310.py b/docs_src/schema_extra_example/tutorial002_py310.py index e84928bb1..27d786867 100644 --- a/docs_src/schema_extra_example/tutorial002_py310.py +++ b/docs_src/schema_extra_example/tutorial002_py310.py @@ -5,10 +5,10 @@ app = FastAPI() class Item(BaseModel): - name: str = Field(example="Foo") - description: str | None = Field(default=None, example="A very nice Item") - price: float = Field(example=35.4) - tax: float | None = Field(default=None, example=3.2) + name: str = Field(examples=["Foo"]) + description: str | None = Field(default=None, examples=["A very nice Item"]) + price: float = Field(examples=[35.4]) + tax: float | None = Field(default=None, examples=[3.2]) @app.put("/items/{item_id}") diff --git a/docs_src/schema_extra_example/tutorial003.py b/docs_src/schema_extra_example/tutorial003.py index ce1736bba..385f3de8a 100644 --- a/docs_src/schema_extra_example/tutorial003.py +++ b/docs_src/schema_extra_example/tutorial003.py @@ -17,12 +17,14 @@ class Item(BaseModel): async def update_item( item_id: int, item: Item = Body( - example={ - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + examples=[ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ], ), ): results = {"item_id": item_id, "item": item} diff --git a/docs_src/schema_extra_example/tutorial003_an.py b/docs_src/schema_extra_example/tutorial003_an.py index 1dec555a9..23675aba1 100644 --- a/docs_src/schema_extra_example/tutorial003_an.py +++ b/docs_src/schema_extra_example/tutorial003_an.py @@ -20,12 +20,14 @@ async def update_item( item: Annotated[ Item, Body( - example={ - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + examples=[ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial003_an_py310.py b/docs_src/schema_extra_example/tutorial003_an_py310.py index 9edaddfb8..bbd2e171e 100644 --- a/docs_src/schema_extra_example/tutorial003_an_py310.py +++ b/docs_src/schema_extra_example/tutorial003_an_py310.py @@ -19,12 +19,14 @@ async def update_item( item: Annotated[ Item, Body( - example={ - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + examples=[ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial003_an_py39.py b/docs_src/schema_extra_example/tutorial003_an_py39.py index fe08847d9..472808561 100644 --- a/docs_src/schema_extra_example/tutorial003_an_py39.py +++ b/docs_src/schema_extra_example/tutorial003_an_py39.py @@ -19,12 +19,14 @@ async def update_item( item: Annotated[ Item, Body( - example={ - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + examples=[ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial003_py310.py b/docs_src/schema_extra_example/tutorial003_py310.py index 1e137101d..2d31619be 100644 --- a/docs_src/schema_extra_example/tutorial003_py310.py +++ b/docs_src/schema_extra_example/tutorial003_py310.py @@ -15,12 +15,14 @@ class Item(BaseModel): async def update_item( item_id: int, item: Item = Body( - example={ - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + examples=[ + { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + } + ], ), ): results = {"item_id": item_id, "item": item} diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004.py index b67edf30c..eb49293fd 100644 --- a/docs_src/schema_extra_example/tutorial004.py +++ b/docs_src/schema_extra_example/tutorial004.py @@ -18,8 +18,8 @@ async def update_item( *, item_id: int, item: Item = Body( - examples={ - "normal": { + examples=[ + { "summary": "A normal example", "description": "A **normal** item works correctly.", "value": { @@ -29,7 +29,7 @@ async def update_item( "tax": 3.2, }, }, - "converted": { + { "summary": "An example with converted data", "description": "FastAPI can convert price `strings` to actual `numbers` automatically", "value": { @@ -37,14 +37,14 @@ async def update_item( "price": "35.4", }, }, - "invalid": { + { "summary": "Invalid data is rejected with an error", "value": { "name": "Baz", "price": "thirty five point four", }, }, - }, + ], ), ): results = {"item_id": item_id, "item": item} diff --git a/docs_src/schema_extra_example/tutorial004_an.py b/docs_src/schema_extra_example/tutorial004_an.py index 82c9a92ac..567ec4702 100644 --- a/docs_src/schema_extra_example/tutorial004_an.py +++ b/docs_src/schema_extra_example/tutorial004_an.py @@ -21,8 +21,8 @@ async def update_item( item: Annotated[ Item, Body( - examples={ - "normal": { + examples=[ + { "summary": "A normal example", "description": "A **normal** item works correctly.", "value": { @@ -32,7 +32,7 @@ async def update_item( "tax": 3.2, }, }, - "converted": { + { "summary": "An example with converted data", "description": "FastAPI can convert price `strings` to actual `numbers` automatically", "value": { @@ -40,14 +40,14 @@ async def update_item( "price": "35.4", }, }, - "invalid": { + { "summary": "Invalid data is rejected with an error", "value": { "name": "Baz", "price": "thirty five point four", }, }, - }, + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial004_an_py310.py b/docs_src/schema_extra_example/tutorial004_an_py310.py index 01f1a486c..026654835 100644 --- a/docs_src/schema_extra_example/tutorial004_an_py310.py +++ b/docs_src/schema_extra_example/tutorial004_an_py310.py @@ -20,8 +20,8 @@ async def update_item( item: Annotated[ Item, Body( - examples={ - "normal": { + examples=[ + { "summary": "A normal example", "description": "A **normal** item works correctly.", "value": { @@ -31,7 +31,7 @@ async def update_item( "tax": 3.2, }, }, - "converted": { + { "summary": "An example with converted data", "description": "FastAPI can convert price `strings` to actual `numbers` automatically", "value": { @@ -39,14 +39,14 @@ async def update_item( "price": "35.4", }, }, - "invalid": { + { "summary": "Invalid data is rejected with an error", "value": { "name": "Baz", "price": "thirty five point four", }, }, - }, + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py index d50e8aa5f..06219ede8 100644 --- a/docs_src/schema_extra_example/tutorial004_an_py39.py +++ b/docs_src/schema_extra_example/tutorial004_an_py39.py @@ -20,8 +20,8 @@ async def update_item( item: Annotated[ Item, Body( - examples={ - "normal": { + examples=[ + { "summary": "A normal example", "description": "A **normal** item works correctly.", "value": { @@ -31,7 +31,7 @@ async def update_item( "tax": 3.2, }, }, - "converted": { + { "summary": "An example with converted data", "description": "FastAPI can convert price `strings` to actual `numbers` automatically", "value": { @@ -39,14 +39,14 @@ async def update_item( "price": "35.4", }, }, - "invalid": { + { "summary": "Invalid data is rejected with an error", "value": { "name": "Baz", "price": "thirty five point four", }, }, - }, + ], ), ], ): diff --git a/docs_src/schema_extra_example/tutorial004_py310.py b/docs_src/schema_extra_example/tutorial004_py310.py index 100a30860..ef2b9d8cb 100644 --- a/docs_src/schema_extra_example/tutorial004_py310.py +++ b/docs_src/schema_extra_example/tutorial004_py310.py @@ -16,8 +16,8 @@ async def update_item( *, item_id: int, item: Item = Body( - examples={ - "normal": { + examples=[ + { "summary": "A normal example", "description": "A **normal** item works correctly.", "value": { @@ -27,7 +27,7 @@ async def update_item( "tax": 3.2, }, }, - "converted": { + { "summary": "An example with converted data", "description": "FastAPI can convert price `strings` to actual `numbers` automatically", "value": { @@ -35,14 +35,14 @@ async def update_item( "price": "35.4", }, }, - "invalid": { + { "summary": "Invalid data is rejected with an error", "value": { "name": "Baz", "price": "thirty five point four", }, }, - }, + ], ), ): results = {"item_id": item_id, "item": item} diff --git a/fastapi/applications.py b/fastapi/applications.py index 9b161c5ec..88f861c1e 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -55,6 +55,7 @@ class FastAPI(Starlette): debug: bool = False, routes: Optional[List[BaseRoute]] = None, title: str = "FastAPI", + summary: Optional[str] = None, description: str = "", version: str = "0.1.0", openapi_url: Optional[str] = "/openapi.json", @@ -85,6 +86,7 @@ class FastAPI(Starlette): root_path_in_servers: bool = True, responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, callbacks: Optional[List[BaseRoute]] = None, + webhooks: Optional[routing.APIRouter] = None, deprecated: Optional[bool] = None, include_in_schema: bool = True, swagger_ui_parameters: Optional[Dict[str, Any]] = None, @@ -95,6 +97,7 @@ class FastAPI(Starlette): ) -> None: self.debug = debug self.title = title + self.summary = summary self.description = description self.version = version self.terms_of_service = terms_of_service @@ -110,7 +113,7 @@ class FastAPI(Starlette): self.swagger_ui_parameters = swagger_ui_parameters self.servers = servers or [] self.extra = extra - self.openapi_version = "3.0.2" + self.openapi_version = "3.1.0" self.openapi_schema: Optional[Dict[str, Any]] = None if self.openapi_url: assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" @@ -123,6 +126,7 @@ class FastAPI(Starlette): "automatic. Check the docs at " "https://fastapi.tiangolo.com/advanced/sub-applications/" ) + self.webhooks = webhooks or routing.APIRouter() self.root_path = root_path or openapi_prefix self.state: State = State() self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {} @@ -215,11 +219,13 @@ class FastAPI(Starlette): title=self.title, version=self.version, openapi_version=self.openapi_version, + summary=self.summary, description=self.description, terms_of_service=self.terms_of_service, contact=self.contact, license_info=self.license_info, routes=self.routes, + webhooks=self.webhooks.routes, tags=self.openapi_tags, servers=self.servers, ) diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index bf335118f..81f67dcc5 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -17,8 +17,8 @@ def get_swagger_ui_html( *, openapi_url: str, title: str, - swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui-bundle.js", - swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@4/swagger-ui.css", + swagger_js_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui-bundle.js", + swagger_css_url: str = "https://cdn.jsdelivr.net/npm/swagger-ui-dist@5/swagger-ui.css", swagger_favicon_url: str = "https://fastapi.tiangolo.com/img/favicon.png", oauth2_redirect_url: Optional[str] = None, init_oauth: Optional[Dict[str, Any]] = None, diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 81a24f389..7420d3b55 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -1,9 +1,10 @@ from enum import Enum -from typing import Any, Callable, Dict, Iterable, List, Optional, Union +from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Union from fastapi.logger import logger from pydantic import AnyUrl, BaseModel, Field -from typing_extensions import Literal +from typing_extensions import Annotated, Literal +from typing_extensions import deprecated as typing_deprecated try: import email_validator # type: ignore @@ -37,6 +38,7 @@ class Contact(BaseModel): class License(BaseModel): name: str + identifier: Optional[str] = None url: Optional[AnyUrl] = None class Config: @@ -45,6 +47,7 @@ class License(BaseModel): class Info(BaseModel): title: str + summary: Optional[str] = None description: Optional[str] = None termsOfService: Optional[str] = None contact: Optional[Contact] = None @@ -56,7 +59,7 @@ class Info(BaseModel): class ServerVariable(BaseModel): - enum: Optional[List[str]] = None + enum: Annotated[Optional[List[str]], Field(min_items=1)] = None default: str description: Optional[str] = None @@ -102,9 +105,42 @@ class ExternalDocumentation(BaseModel): class Schema(BaseModel): + # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-the-json-schema-core-vocabu + # Core Vocabulary + schema_: Optional[str] = Field(default=None, alias="$schema") + vocabulary: Optional[str] = Field(default=None, alias="$vocabulary") + id: Optional[str] = Field(default=None, alias="$id") + anchor: Optional[str] = Field(default=None, alias="$anchor") + dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") ref: Optional[str] = Field(default=None, alias="$ref") - title: Optional[str] = None - multipleOf: Optional[float] = None + dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") + defs: Optional[Dict[str, "Schema"]] = Field(default=None, alias="$defs") + comment: Optional[str] = Field(default=None, alias="$comment") + # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s + # A Vocabulary for Applying Subschemas + allOf: Optional[List["Schema"]] = None + anyOf: Optional[List["Schema"]] = None + oneOf: Optional[List["Schema"]] = None + not_: Optional["Schema"] = Field(default=None, alias="not") + if_: Optional["Schema"] = Field(default=None, alias="if") + then: Optional["Schema"] = None + else_: Optional["Schema"] = Field(default=None, alias="else") + dependentSchemas: Optional[Dict[str, "Schema"]] = None + prefixItems: Optional[List["Schema"]] = None + items: Optional[Union["Schema", List["Schema"]]] = None + contains: Optional["Schema"] = None + properties: Optional[Dict[str, "Schema"]] = None + patternProperties: Optional[Dict[str, "Schema"]] = None + additionalProperties: Optional["Schema"] = None + propertyNames: Optional["Schema"] = None + unevaluatedItems: Optional["Schema"] = None + unevaluatedProperties: Optional["Schema"] = None + # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural + # A Vocabulary for Structural Validation + type: Optional[str] = None + enum: Optional[List[Any]] = None + const: Optional[Any] = None + multipleOf: Optional[float] = Field(default=None, gt=0) maximum: Optional[float] = None exclusiveMaximum: Optional[float] = None minimum: Optional[float] = None @@ -115,29 +151,41 @@ class Schema(BaseModel): maxItems: Optional[int] = Field(default=None, ge=0) minItems: Optional[int] = Field(default=None, ge=0) uniqueItems: Optional[bool] = None + maxContains: Optional[int] = Field(default=None, ge=0) + minContains: Optional[int] = Field(default=None, ge=0) maxProperties: Optional[int] = Field(default=None, ge=0) minProperties: Optional[int] = Field(default=None, ge=0) required: Optional[List[str]] = None - enum: Optional[List[Any]] = None - type: Optional[str] = None - allOf: Optional[List["Schema"]] = None - oneOf: Optional[List["Schema"]] = None - anyOf: Optional[List["Schema"]] = None - not_: Optional["Schema"] = Field(default=None, alias="not") - items: Optional[Union["Schema", List["Schema"]]] = None - properties: Optional[Dict[str, "Schema"]] = None - additionalProperties: Optional[Union["Schema", Reference, bool]] = None - description: Optional[str] = None + dependentRequired: Optional[Dict[str, Set[str]]] = None + # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c + # Vocabularies for Semantic Content With "format" format: Optional[str] = None + # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-the-conten + # A Vocabulary for the Contents of String-Encoded Data + contentEncoding: Optional[str] = None + contentMediaType: Optional[str] = None + contentSchema: Optional["Schema"] = None + # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta + # A Vocabulary for Basic Meta-Data Annotations + title: Optional[str] = None + description: Optional[str] = None default: Optional[Any] = None - nullable: Optional[bool] = None - discriminator: Optional[Discriminator] = None + deprecated: Optional[bool] = None readOnly: Optional[bool] = None writeOnly: Optional[bool] = None + examples: Optional[List[Any]] = None + # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object + # Schema Object + discriminator: Optional[Discriminator] = None xml: Optional[XML] = None externalDocs: Optional[ExternalDocumentation] = None - example: Optional[Any] = None - deprecated: Optional[bool] = None + example: Annotated[ + Optional[Any], + typing_deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = None class Config: extra: str = "allow" @@ -248,7 +296,7 @@ class Operation(BaseModel): parameters: Optional[List[Union[Parameter, Reference]]] = None requestBody: Optional[Union[RequestBody, Reference]] = None # Using Any for Specification Extensions - responses: Dict[str, Union[Response, Any]] + responses: Optional[Dict[str, Union[Response, Any]]] = None callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None deprecated: Optional[bool] = None security: Optional[List[Dict[str, List[str]]]] = None @@ -375,6 +423,7 @@ class Components(BaseModel): links: Optional[Dict[str, Union[Link, Reference]]] = None # Using Any for Specification Extensions callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None + pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None class Config: extra = "allow" @@ -392,9 +441,11 @@ class Tag(BaseModel): class OpenAPI(BaseModel): openapi: str info: Info + jsonSchemaDialect: Optional[str] = None servers: Optional[List[Server]] = None # Using Any for Specification Extensions - paths: Dict[str, Union[PathItem, Any]] + paths: Optional[Dict[str, Union[PathItem, Any]]] = None + webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None components: Optional[Components] = None security: Optional[List[Dict[str, List[str]]]] = None tags: Optional[List[Tag]] = None diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 6d736647b..609fe4389 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -106,9 +106,7 @@ def get_openapi_operation_parameters( } if field_info.description: parameter["description"] = field_info.description - if field_info.examples: - parameter["examples"] = jsonable_encoder(field_info.examples) - elif field_info.example != Undefined: + if field_info.example != Undefined: parameter["example"] = jsonable_encoder(field_info.example) if field_info.deprecated: parameter["deprecated"] = field_info.deprecated @@ -134,9 +132,7 @@ def get_openapi_operation_request_body( if required: request_body_oai["required"] = required request_media_content: Dict[str, Any] = {"schema": body_schema} - if field_info.examples: - request_media_content["examples"] = jsonable_encoder(field_info.examples) - elif field_info.example != Undefined: + if field_info.example != Undefined: request_media_content["example"] = jsonable_encoder(field_info.example) request_body_oai["content"] = {request_media_type: request_media_content} return request_body_oai @@ -392,9 +388,11 @@ def get_openapi( *, title: str, version: str, - openapi_version: str = "3.0.2", + openapi_version: str = "3.1.0", + summary: Optional[str] = None, description: Optional[str] = None, routes: Sequence[BaseRoute], + webhooks: Optional[Sequence[BaseRoute]] = None, tags: Optional[List[Dict[str, Any]]] = None, servers: Optional[List[Dict[str, Union[str, Any]]]] = None, terms_of_service: Optional[str] = None, @@ -402,6 +400,8 @@ def get_openapi( license_info: Optional[Dict[str, Union[str, Any]]] = None, ) -> Dict[str, Any]: info: Dict[str, Any] = {"title": title, "version": version} + if summary: + info["summary"] = summary if description: info["description"] = description if terms_of_service: @@ -415,13 +415,14 @@ def get_openapi( output["servers"] = servers components: Dict[str, Dict[str, Any]] = {} paths: Dict[str, Dict[str, Any]] = {} + webhook_paths: Dict[str, Dict[str, Any]] = {} operation_ids: Set[str] = set() - flat_models = get_flat_models_from_routes(routes) + flat_models = get_flat_models_from_routes(list(routes or []) + list(webhooks or [])) model_name_map = get_model_name_map(flat_models) definitions = get_model_definitions( flat_models=flat_models, model_name_map=model_name_map ) - for route in routes: + for route in routes or []: if isinstance(route, routing.APIRoute): result = get_openapi_path( route=route, model_name_map=model_name_map, operation_ids=operation_ids @@ -436,11 +437,30 @@ def get_openapi( ) if path_definitions: definitions.update(path_definitions) + for webhook in webhooks or []: + if isinstance(webhook, routing.APIRoute): + result = get_openapi_path( + route=webhook, + model_name_map=model_name_map, + operation_ids=operation_ids, + ) + if result: + path, security_schemes, path_definitions = result + if path: + webhook_paths.setdefault(webhook.path_format, {}).update(path) + if security_schemes: + components.setdefault("securitySchemes", {}).update( + security_schemes + ) + if path_definitions: + definitions.update(path_definitions) if definitions: components["schemas"] = {k: definitions[k] for k in sorted(definitions)} if components: output["components"] = components output["paths"] = paths + if webhook_paths: + output["webhooks"] = webhook_paths if tags: output["tags"] = tags return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index 75f054e9d..2f5818c85 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -1,7 +1,8 @@ -from typing import Any, Callable, Dict, Optional, Sequence +from typing import Any, Callable, List, Optional, Sequence from fastapi import params from pydantic.fields import Undefined +from typing_extensions import Annotated, deprecated def Path( # noqa: N802 @@ -17,8 +18,14 @@ def Path( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -56,8 +63,14 @@ def Query( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -96,8 +109,14 @@ def Header( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -136,8 +155,14 @@ def Cookie( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -177,8 +202,14 @@ def Body( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ) -> Any: return params.Body( @@ -215,8 +246,14 @@ def Form( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ) -> Any: return params.Form( @@ -252,8 +289,14 @@ def File( # noqa: N802 min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ) -> Any: return params.File( diff --git a/fastapi/params.py b/fastapi/params.py index 16c5c309a..4069f2cda 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -1,7 +1,9 @@ +import warnings from enum import Enum -from typing import Any, Callable, Dict, Optional, Sequence +from typing import Any, Callable, List, Optional, Sequence from pydantic.fields import FieldInfo, Undefined +from typing_extensions import Annotated, deprecated class ParamTypes(Enum): @@ -28,16 +30,30 @@ class Param(FieldInfo): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, ): self.deprecated = deprecated + if example is not Undefined: + warnings.warn( + "`example` has been depreacated, please use `examples` instead", + category=DeprecationWarning, + stacklevel=1, + ) self.example = example - self.examples = examples self.include_in_schema = include_in_schema + extra_kwargs = {**extra} + if examples: + extra_kwargs["examples"] = examples super().__init__( default=default, alias=alias, @@ -50,7 +66,7 @@ class Param(FieldInfo): min_length=min_length, max_length=max_length, regex=regex, - **extra, + **extra_kwargs, ) def __repr__(self) -> str: @@ -74,8 +90,14 @@ class Path(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -119,8 +141,14 @@ class Query(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -163,8 +191,14 @@ class Header(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -207,8 +241,14 @@ class Cookie(Param): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, deprecated: Optional[bool] = None, include_in_schema: bool = True, **extra: Any, @@ -250,14 +290,28 @@ class Body(FieldInfo): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ): self.embed = embed self.media_type = media_type + if example is not Undefined: + warnings.warn( + "`example` has been depreacated, please use `examples` instead", + category=DeprecationWarning, + stacklevel=1, + ) self.example = example - self.examples = examples + extra_kwargs = {**extra} + if examples is not None: + extra_kwargs["examples"] = examples super().__init__( default=default, alias=alias, @@ -270,7 +324,7 @@ class Body(FieldInfo): min_length=min_length, max_length=max_length, regex=regex, - **extra, + **extra_kwargs, ) def __repr__(self) -> str: @@ -293,8 +347,14 @@ class Form(Body): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ): super().__init__( @@ -333,8 +393,14 @@ class File(Form): min_length: Optional[int] = None, max_length: Optional[int] = None, regex: Optional[str] = None, - example: Any = Undefined, - examples: Optional[Dict[str, Any]] = None, + examples: Optional[List[Any]] = None, + example: Annotated[ + Optional[Any], + deprecated( + "Deprecated in OpenAPI 3.1.0 that now uses JSON Schema 2020-12, " + "although still supported. Use examples instead." + ), + ] = Undefined, **extra: Any, ): super().__init__( diff --git a/pyproject.toml b/pyproject.toml index 5c0d3c48e..61dbf7629 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ classifiers = [ dependencies = [ "starlette>=0.27.0,<0.28.0", "pydantic>=1.7.4,!=1.8,!=1.8.1,<2.0.0", + "typing-extensions>=4.5.0" ] dynamic = ["version"] diff --git a/tests/test_additional_properties.py b/tests/test_additional_properties.py index 516a569e4..be14d10ed 100644 --- a/tests/test_additional_properties.py +++ b/tests/test_additional_properties.py @@ -29,7 +29,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/foo": { diff --git a/tests/test_additional_response_extra.py b/tests/test_additional_response_extra.py index d62638c8f..55be19bad 100644 --- a/tests/test_additional_response_extra.py +++ b/tests/test_additional_response_extra.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_additional_responses_bad.py b/tests/test_additional_responses_bad.py index d2eb4d7a1..36df07f46 100644 --- a/tests/test_additional_responses_bad.py +++ b/tests/test_additional_responses_bad.py @@ -11,7 +11,7 @@ async def a(): openapi_schema = { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a": { diff --git a/tests/test_additional_responses_custom_model_in_callback.py b/tests/test_additional_responses_custom_model_in_callback.py index 5c08eaa6d..397159142 100644 --- a/tests/test_additional_responses_custom_model_in_callback.py +++ b/tests/test_additional_responses_custom_model_in_callback.py @@ -32,7 +32,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_additional_responses_custom_validationerror.py b/tests/test_additional_responses_custom_validationerror.py index 052602768..9fec5c96d 100644 --- a/tests/test_additional_responses_custom_validationerror.py +++ b/tests/test_additional_responses_custom_validationerror.py @@ -37,7 +37,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a/{id}": { diff --git a/tests/test_additional_responses_default_validationerror.py b/tests/test_additional_responses_default_validationerror.py index 58de46ff6..153f04f57 100644 --- a/tests/test_additional_responses_default_validationerror.py +++ b/tests/test_additional_responses_default_validationerror.py @@ -16,7 +16,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a/{id}": { diff --git a/tests/test_additional_responses_response_class.py b/tests/test_additional_responses_response_class.py index 6746760f0..68753561c 100644 --- a/tests/test_additional_responses_response_class.py +++ b/tests/test_additional_responses_response_class.py @@ -42,7 +42,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a": { diff --git a/tests/test_additional_responses_router.py b/tests/test_additional_responses_router.py index 58d54b733..71cabc7c3 100644 --- a/tests/test_additional_responses_router.py +++ b/tests/test_additional_responses_router.py @@ -85,7 +85,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a": { diff --git a/tests/test_annotated.py b/tests/test_annotated.py index a4f42b038..5a70c4541 100644 --- a/tests/test_annotated.py +++ b/tests/test_annotated.py @@ -118,7 +118,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/default": { diff --git a/tests/test_application.py b/tests/test_application.py index e5f2f4387..b036e67af 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -55,7 +55,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/api_route": { diff --git a/tests/test_custom_route_class.py b/tests/test_custom_route_class.py index d1b18ef1d..55374584b 100644 --- a/tests/test_custom_route_class.py +++ b/tests/test_custom_route_class.py @@ -75,7 +75,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a/": { diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py index 285fdf1ab..4f4f3166c 100644 --- a/tests/test_dependency_duplicates.py +++ b/tests/test_dependency_duplicates.py @@ -86,7 +86,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/with-duplicates": { diff --git a/tests/test_deprecated_openapi_prefix.py b/tests/test_deprecated_openapi_prefix.py index 688b9837f..ec7366d2a 100644 --- a/tests/test_deprecated_openapi_prefix.py +++ b/tests/test_deprecated_openapi_prefix.py @@ -22,7 +22,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/app": { diff --git a/tests/test_duplicate_models_openapi.py b/tests/test_duplicate_models_openapi.py index 116b2006a..83e86d231 100644 --- a/tests/test_duplicate_models_openapi.py +++ b/tests/test_duplicate_models_openapi.py @@ -36,7 +36,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_enforce_once_required_parameter.py b/tests/test_enforce_once_required_parameter.py index bf05aa585..b64f8341b 100644 --- a/tests/test_enforce_once_required_parameter.py +++ b/tests/test_enforce_once_required_parameter.py @@ -57,7 +57,7 @@ expected_schema = { } }, "info": {"title": "FastAPI", "version": "0.1.0"}, - "openapi": "3.0.2", + "openapi": "3.1.0", "paths": { "/foo": { "get": { diff --git a/tests/test_extra_routes.py b/tests/test_extra_routes.py index c0db62c19..fa95d061c 100644 --- a/tests/test_extra_routes.py +++ b/tests/test_extra_routes.py @@ -99,7 +99,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_filter_pydantic_sub_model.py b/tests/test_filter_pydantic_sub_model.py index 15b15f862..6ee928d07 100644 --- a/tests/test_filter_pydantic_sub_model.py +++ b/tests/test_filter_pydantic_sub_model.py @@ -66,7 +66,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/model/{name}": { diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py index 0b519f859..c5ef5182b 100644 --- a/tests/test_generate_unique_id_function.py +++ b/tests/test_generate_unique_id_function.py @@ -48,7 +48,7 @@ def test_top_level_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -249,7 +249,7 @@ def test_router_overrides_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -450,7 +450,7 @@ def test_router_include_overrides_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -661,7 +661,7 @@ def test_subrouter_top_level_include_overrides_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -928,7 +928,7 @@ def test_router_path_operation_overrides_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -1136,7 +1136,7 @@ def test_app_path_operation_overrides_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { @@ -1353,7 +1353,7 @@ def test_callback_override_generate_unique_id(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_get_request_body.py b/tests/test_get_request_body.py index 541147fa8..cc567b88f 100644 --- a/tests/test_get_request_body.py +++ b/tests/test_get_request_body.py @@ -29,7 +29,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/product": { diff --git a/tests/test_include_router_defaults_overrides.py b/tests/test_include_router_defaults_overrides.py index ced56c84d..33baa25e6 100644 --- a/tests/test_include_router_defaults_overrides.py +++ b/tests/test_include_router_defaults_overrides.py @@ -443,7 +443,7 @@ def test_openapi(): assert issubclass(w[-1].category, UserWarning) assert "Duplicate Operation ID" in str(w[-1].message) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/override1": { diff --git a/tests/test_modules_same_name_body/test_main.py b/tests/test_modules_same_name_body/test_main.py index 1ebcaee8c..cc165bdca 100644 --- a/tests/test_modules_same_name_body/test_main.py +++ b/tests/test_modules_same_name_body/test_main.py @@ -35,7 +35,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a/compute": { diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py index 358684bc5..96043aa35 100644 --- a/tests/test_multi_body_errors.py +++ b/tests/test_multi_body_errors.py @@ -80,7 +80,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py index e7a833f2b..c1f0678d0 100644 --- a/tests/test_multi_query_errors.py +++ b/tests/test_multi_query_errors.py @@ -46,7 +46,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_openapi_query_parameter_extension.py b/tests/test_openapi_query_parameter_extension.py index 8a9086ebe..6f62e6726 100644 --- a/tests/test_openapi_query_parameter_extension.py +++ b/tests/test_openapi_query_parameter_extension.py @@ -42,7 +42,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_openapi_route_extensions.py b/tests/test_openapi_route_extensions.py index 943dc43f2..3a3099436 100644 --- a/tests/test_openapi_route_extensions.py +++ b/tests/test_openapi_route_extensions.py @@ -22,7 +22,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_openapi_servers.py b/tests/test_openapi_servers.py index 26abeaa12..11cd795ac 100644 --- a/tests/test_openapi_servers.py +++ b/tests/test_openapi_servers.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "servers": [ {"url": "/", "description": "Default, relative server"}, diff --git a/tests/test_param_in_path_and_dependency.py b/tests/test_param_in_path_and_dependency.py index 0aef7ac7b..08eb0f40f 100644 --- a/tests/test_param_in_path_and_dependency.py +++ b/tests/test_param_in_path_and_dependency.py @@ -25,7 +25,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/{user_id}": { diff --git a/tests/test_param_include_in_schema.py b/tests/test_param_include_in_schema.py index d0c29f7b2..26201e9e2 100644 --- a/tests/test_param_include_in_schema.py +++ b/tests/test_param_include_in_schema.py @@ -34,7 +34,7 @@ async def hidden_query( openapi_schema = { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/hidden_cookie": { diff --git a/tests/test_put_no_body.py b/tests/test_put_no_body.py index a02d1152c..8f4c82532 100644 --- a/tests/test_put_no_body.py +++ b/tests/test_put_no_body.py @@ -28,7 +28,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_repeated_dependency_schema.py b/tests/test_repeated_dependency_schema.py index ca0305184..d7d0dfa05 100644 --- a/tests/test_repeated_dependency_schema.py +++ b/tests/test_repeated_dependency_schema.py @@ -50,7 +50,7 @@ schema = { } }, "info": {"title": "FastAPI", "version": "0.1.0"}, - "openapi": "3.0.2", + "openapi": "3.1.0", "paths": { "/": { "get": { diff --git a/tests/test_repeated_parameter_alias.py b/tests/test_repeated_parameter_alias.py index c656a161d..fd72eaab2 100644 --- a/tests/test_repeated_parameter_alias.py +++ b/tests/test_repeated_parameter_alias.py @@ -58,7 +58,7 @@ def test_openapi_schema(): } }, "info": {"title": "FastAPI", "version": "0.1.0"}, - "openapi": "3.0.2", + "openapi": "3.1.0", "paths": { "/{repeated_alias}": { "get": { diff --git a/tests/test_reponse_set_reponse_code_empty.py b/tests/test_reponse_set_reponse_code_empty.py index 14770fed0..bf3aa758c 100644 --- a/tests/test_reponse_set_reponse_code_empty.py +++ b/tests/test_reponse_set_reponse_code_empty.py @@ -32,7 +32,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/{id}": { diff --git a/tests/test_request_body_parameters_media_type.py b/tests/test_request_body_parameters_media_type.py index 32f6c6a72..8424bf551 100644 --- a/tests/test_request_body_parameters_media_type.py +++ b/tests/test_request_body_parameters_media_type.py @@ -41,7 +41,7 @@ def test_openapi_schema(): assert response.status_code == 200, response.text # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/products": { diff --git a/tests/test_response_by_alias.py b/tests/test_response_by_alias.py index 1861a40fa..c3ff5b1d2 100644 --- a/tests/test_response_by_alias.py +++ b/tests/test_response_by_alias.py @@ -138,7 +138,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/dict": { diff --git a/tests/test_response_class_no_mediatype.py b/tests/test_response_class_no_mediatype.py index 2d75c7535..706929ac3 100644 --- a/tests/test_response_class_no_mediatype.py +++ b/tests/test_response_class_no_mediatype.py @@ -42,7 +42,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a": { diff --git a/tests/test_response_code_no_body.py b/tests/test_response_code_no_body.py index 3851a325d..3ca8708f1 100644 --- a/tests/test_response_code_no_body.py +++ b/tests/test_response_code_no_body.py @@ -50,7 +50,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/a": { diff --git a/tests/test_response_model_as_return_annotation.py b/tests/test_response_model_as_return_annotation.py index 7decdff7d..7a0cf47ec 100644 --- a/tests/test_response_model_as_return_annotation.py +++ b/tests/test_response_model_as_return_annotation.py @@ -507,7 +507,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/no_response_model-no_annotation-return_model": { diff --git a/tests/test_response_model_sub_types.py b/tests/test_response_model_sub_types.py index e462006ff..660bcee1b 100644 --- a/tests/test_response_model_sub_types.py +++ b/tests/test_response_model_sub_types.py @@ -50,7 +50,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/valid1": { diff --git a/tests/test_schema_extra_examples.py b/tests/test_schema_extra_examples.py index 41021a983..45caa1615 100644 --- a/tests/test_schema_extra_examples.py +++ b/tests/test_schema_extra_examples.py @@ -1,240 +1,220 @@ from typing import Union +import pytest from fastapi import Body, Cookie, FastAPI, Header, Path, Query from fastapi.testclient import TestClient from pydantic import BaseModel -app = FastAPI() - -class Item(BaseModel): - data: str - - class Config: - schema_extra = {"example": {"data": "Data in schema_extra"}} - - -@app.post("/schema_extra/") -def schema_extra(item: Item): - return item - - -@app.post("/example/") -def example(item: Item = Body(example={"data": "Data in Body example"})): - return item - - -@app.post("/examples/") -def examples( - item: Item = Body( - examples={ - "example1": { - "summary": "example1 summary", - "value": {"data": "Data in Body examples, example1"}, - }, - "example2": {"value": {"data": "Data in Body examples, example2"}}, - }, - ) -): - return item - - -@app.post("/example_examples/") -def example_examples( - item: Item = Body( - example={"data": "Overridden example"}, - examples={ - "example1": {"value": {"data": "examples example_examples 1"}}, - "example2": {"value": {"data": "examples example_examples 2"}}, - }, - ) -): - return item - - -# TODO: enable these tests once/if Form(embed=False) is supported -# TODO: In that case, define if File() should support example/examples too -# @app.post("/form_example") -# def form_example(firstname: str = Form(example="John")): -# return firstname - - -# @app.post("/form_examples") -# def form_examples( -# lastname: str = Form( -# ..., -# examples={ -# "example1": {"summary": "last name summary", "value": "Doe"}, -# "example2": {"value": "Doesn't"}, -# }, -# ), -# ): -# return lastname - - -# @app.post("/form_example_examples") -# def form_example_examples( -# lastname: str = Form( -# ..., -# example="Doe overridden", -# examples={ -# "example1": {"summary": "last name summary", "value": "Doe"}, -# "example2": {"value": "Doesn't"}, -# }, -# ), -# ): -# return lastname - - -@app.get("/path_example/{item_id}") -def path_example( - item_id: str = Path( - example="item_1", - ), -): - return item_id - - -@app.get("/path_examples/{item_id}") -def path_examples( - item_id: str = Path( - examples={ - "example1": {"summary": "item ID summary", "value": "item_1"}, - "example2": {"value": "item_2"}, - }, - ), -): - return item_id - - -@app.get("/path_example_examples/{item_id}") -def path_example_examples( - item_id: str = Path( - example="item_overridden", - examples={ - "example1": {"summary": "item ID summary", "value": "item_1"}, - "example2": {"value": "item_2"}, - }, - ), -): - return item_id - - -@app.get("/query_example/") -def query_example( - data: Union[str, None] = Query( - default=None, - example="query1", - ), -): - return data - - -@app.get("/query_examples/") -def query_examples( - data: Union[str, None] = Query( - default=None, - examples={ - "example1": {"summary": "Query example 1", "value": "query1"}, - "example2": {"value": "query2"}, - }, - ), -): - return data - - -@app.get("/query_example_examples/") -def query_example_examples( - data: Union[str, None] = Query( - default=None, - example="query_overridden", - examples={ - "example1": {"summary": "Query example 1", "value": "query1"}, - "example2": {"value": "query2"}, - }, - ), -): - return data - - -@app.get("/header_example/") -def header_example( - data: Union[str, None] = Header( - default=None, - example="header1", - ), -): - return data - - -@app.get("/header_examples/") -def header_examples( - data: Union[str, None] = Header( - default=None, - examples={ - "example1": {"summary": "header example 1", "value": "header1"}, - "example2": {"value": "header2"}, - }, - ), -): - return data - - -@app.get("/header_example_examples/") -def header_example_examples( - data: Union[str, None] = Header( - default=None, - example="header_overridden", - examples={ - "example1": {"summary": "Query example 1", "value": "header1"}, - "example2": {"value": "header2"}, - }, - ), -): - return data - - -@app.get("/cookie_example/") -def cookie_example( - data: Union[str, None] = Cookie( - default=None, - example="cookie1", - ), -): - return data - - -@app.get("/cookie_examples/") -def cookie_examples( - data: Union[str, None] = Cookie( - default=None, - examples={ - "example1": {"summary": "cookie example 1", "value": "cookie1"}, - "example2": {"value": "cookie2"}, - }, - ), -): - return data - - -@app.get("/cookie_example_examples/") -def cookie_example_examples( - data: Union[str, None] = Cookie( - default=None, - example="cookie_overridden", - examples={ - "example1": {"summary": "Query example 1", "value": "cookie1"}, - "example2": {"value": "cookie2"}, - }, - ), -): - return data - - -client = TestClient(app) +def create_app(): + app = FastAPI() + + class Item(BaseModel): + data: str + + class Config: + schema_extra = {"example": {"data": "Data in schema_extra"}} + + @app.post("/schema_extra/") + def schema_extra(item: Item): + return item + + with pytest.warns(DeprecationWarning): + + @app.post("/example/") + def example(item: Item = Body(example={"data": "Data in Body example"})): + return item + + @app.post("/examples/") + def examples( + item: Item = Body( + examples=[ + {"data": "Data in Body examples, example1"}, + {"data": "Data in Body examples, example2"}, + ], + ) + ): + return item + + with pytest.warns(DeprecationWarning): + + @app.post("/example_examples/") + def example_examples( + item: Item = Body( + example={"data": "Overridden example"}, + examples=[ + {"data": "examples example_examples 1"}, + {"data": "examples example_examples 2"}, + ], + ) + ): + return item + + # TODO: enable these tests once/if Form(embed=False) is supported + # TODO: In that case, define if File() should support example/examples too + # @app.post("/form_example") + # def form_example(firstname: str = Form(example="John")): + # return firstname + + # @app.post("/form_examples") + # def form_examples( + # lastname: str = Form( + # ..., + # examples={ + # "example1": {"summary": "last name summary", "value": "Doe"}, + # "example2": {"value": "Doesn't"}, + # }, + # ), + # ): + # return lastname + + # @app.post("/form_example_examples") + # def form_example_examples( + # lastname: str = Form( + # ..., + # example="Doe overridden", + # examples={ + # "example1": {"summary": "last name summary", "value": "Doe"}, + # "example2": {"value": "Doesn't"}, + # }, + # ), + # ): + # return lastname + + with pytest.warns(DeprecationWarning): + + @app.get("/path_example/{item_id}") + def path_example( + item_id: str = Path( + example="item_1", + ), + ): + return item_id + + @app.get("/path_examples/{item_id}") + def path_examples( + item_id: str = Path( + examples=["item_1", "item_2"], + ), + ): + return item_id + + with pytest.warns(DeprecationWarning): + + @app.get("/path_example_examples/{item_id}") + def path_example_examples( + item_id: str = Path( + example="item_overridden", + examples=["item_1", "item_2"], + ), + ): + return item_id + + with pytest.warns(DeprecationWarning): + + @app.get("/query_example/") + def query_example( + data: Union[str, None] = Query( + default=None, + example="query1", + ), + ): + return data + + @app.get("/query_examples/") + def query_examples( + data: Union[str, None] = Query( + default=None, + examples=["query1", "query2"], + ), + ): + return data + + with pytest.warns(DeprecationWarning): + + @app.get("/query_example_examples/") + def query_example_examples( + data: Union[str, None] = Query( + default=None, + example="query_overridden", + examples=["query1", "query2"], + ), + ): + return data + + with pytest.warns(DeprecationWarning): + + @app.get("/header_example/") + def header_example( + data: Union[str, None] = Header( + default=None, + example="header1", + ), + ): + return data + + @app.get("/header_examples/") + def header_examples( + data: Union[str, None] = Header( + default=None, + examples=[ + "header1", + "header2", + ], + ), + ): + return data + + with pytest.warns(DeprecationWarning): + + @app.get("/header_example_examples/") + def header_example_examples( + data: Union[str, None] = Header( + default=None, + example="header_overridden", + examples=["header1", "header2"], + ), + ): + return data + + with pytest.warns(DeprecationWarning): + + @app.get("/cookie_example/") + def cookie_example( + data: Union[str, None] = Cookie( + default=None, + example="cookie1", + ), + ): + return data + + @app.get("/cookie_examples/") + def cookie_examples( + data: Union[str, None] = Cookie( + default=None, + examples=["cookie1", "cookie2"], + ), + ): + return data + + with pytest.warns(DeprecationWarning): + + @app.get("/cookie_example_examples/") + def cookie_example_examples( + data: Union[str, None] = Cookie( + default=None, + example="cookie_overridden", + examples=["cookie1", "cookie2"], + ), + ): + return data + + return app def test_call_api(): + app = create_app() + client = TestClient(app) response = client.post("/schema_extra/", json={"data": "Foo"}) assert response.status_code == 200, response.text response = client.post("/example/", json={"data": "Foo"}) @@ -277,10 +257,12 @@ def test_openapi_schema(): * Body(example={}) overrides schema_extra in pydantic model * Body(examples{}) overrides Body(example={}) and schema_extra in pydantic model """ + app = create_app() + client = TestClient(app) response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/schema_extra/": { @@ -351,20 +333,14 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "example1": { - "summary": "example1 summary", - "value": { - "data": "Data in Body examples, example1" - }, - }, - "example2": { - "value": { - "data": "Data in Body examples, example2" - } - }, - }, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + {"data": "Data in Body examples, example1"}, + {"data": "Data in Body examples, example2"}, + ], + } } }, "required": True, @@ -394,15 +370,15 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "example1": { - "value": {"data": "examples example_examples 1"} - }, - "example2": { - "value": {"data": "examples example_examples 2"} - }, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + {"data": "examples example_examples 1"}, + {"data": "examples example_examples 2"}, + ], }, + "example": {"data": "Overridden example"}, } }, "required": True, @@ -463,13 +439,10 @@ def test_openapi_schema(): "parameters": [ { "required": True, - "schema": {"title": "Item Id", "type": "string"}, - "examples": { - "example1": { - "summary": "item ID summary", - "value": "item_1", - }, - "example2": {"value": "item_2"}, + "schema": { + "title": "Item Id", + "type": "string", + "examples": ["item_1", "item_2"], }, "name": "item_id", "in": "path", @@ -500,14 +473,12 @@ def test_openapi_schema(): "parameters": [ { "required": True, - "schema": {"title": "Item Id", "type": "string"}, - "examples": { - "example1": { - "summary": "item ID summary", - "value": "item_1", - }, - "example2": {"value": "item_2"}, + "schema": { + "title": "Item Id", + "type": "string", + "examples": ["item_1", "item_2"], }, + "example": "item_overridden", "name": "item_id", "in": "path", } @@ -568,13 +539,10 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "Query example 1", - "value": "query1", - }, - "example2": {"value": "query2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["query1", "query2"], }, "name": "data", "in": "query", @@ -605,14 +573,12 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "Query example 1", - "value": "query1", - }, - "example2": {"value": "query2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["query1", "query2"], }, + "example": "query_overridden", "name": "data", "in": "query", } @@ -642,7 +608,7 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, + "schema": {"type": "string", "title": "Data"}, "example": "header1", "name": "data", "in": "header", @@ -673,13 +639,10 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "header example 1", - "value": "header1", - }, - "example2": {"value": "header2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["header1", "header2"], }, "name": "data", "in": "header", @@ -710,14 +673,12 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "Query example 1", - "value": "header1", - }, - "example2": {"value": "header2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["header1", "header2"], }, + "example": "header_overridden", "name": "data", "in": "header", } @@ -747,7 +708,7 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, + "schema": {"type": "string", "title": "Data"}, "example": "cookie1", "name": "data", "in": "cookie", @@ -778,13 +739,10 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "cookie example 1", - "value": "cookie1", - }, - "example2": {"value": "cookie2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["cookie1", "cookie2"], }, "name": "data", "in": "cookie", @@ -815,14 +773,12 @@ def test_openapi_schema(): "parameters": [ { "required": False, - "schema": {"title": "Data", "type": "string"}, - "examples": { - "example1": { - "summary": "Query example 1", - "value": "cookie1", - }, - "example2": {"value": "cookie2"}, + "schema": { + "type": "string", + "title": "Data", + "examples": ["cookie1", "cookie2"], }, + "example": "cookie_overridden", "name": "data", "in": "cookie", } diff --git a/tests/test_security_api_key_cookie.py b/tests/test_security_api_key_cookie.py index b1c648c55..4ddb8e2ee 100644 --- a/tests/test_security_api_key_cookie.py +++ b/tests/test_security_api_key_cookie.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_cookie_description.py b/tests/test_security_api_key_cookie_description.py index ac8b4abf8..d99d616e0 100644 --- a/tests/test_security_api_key_cookie_description.py +++ b/tests/test_security_api_key_cookie_description.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_cookie_optional.py b/tests/test_security_api_key_cookie_optional.py index b8c440c9d..cb5590168 100644 --- a/tests/test_security_api_key_cookie_optional.py +++ b/tests/test_security_api_key_cookie_optional.py @@ -48,7 +48,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_header.py b/tests/test_security_api_key_header.py index 96ad80b54..1ff883703 100644 --- a/tests/test_security_api_key_header.py +++ b/tests/test_security_api_key_header.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_header_description.py b/tests/test_security_api_key_header_description.py index 382f53dd7..27f9d0f29 100644 --- a/tests/test_security_api_key_header_description.py +++ b/tests/test_security_api_key_header_description.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_header_optional.py b/tests/test_security_api_key_header_optional.py index adfb20ba0..6f9682a64 100644 --- a/tests/test_security_api_key_header_optional.py +++ b/tests/test_security_api_key_header_optional.py @@ -47,7 +47,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_query.py b/tests/test_security_api_key_query.py index da98eafd6..dc7a0a621 100644 --- a/tests/test_security_api_key_query.py +++ b/tests/test_security_api_key_query.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_query_description.py b/tests/test_security_api_key_query_description.py index 3c08afc5f..35dc7743a 100644 --- a/tests/test_security_api_key_query_description.py +++ b/tests/test_security_api_key_query_description.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_api_key_query_optional.py b/tests/test_security_api_key_query_optional.py index 99a26cfd0..4cc134bd4 100644 --- a/tests/test_security_api_key_query_optional.py +++ b/tests/test_security_api_key_query_optional.py @@ -47,7 +47,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_base.py b/tests/test_security_http_base.py index d3a754203..51928bafd 100644 --- a/tests/test_security_http_base.py +++ b/tests/test_security_http_base.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_base_description.py b/tests/test_security_http_base_description.py index 3d7d15016..bc79f3242 100644 --- a/tests/test_security_http_base_description.py +++ b/tests/test_security_http_base_description.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_base_optional.py b/tests/test_security_http_base_optional.py index 180c9110e..dd4d76843 100644 --- a/tests/test_security_http_base_optional.py +++ b/tests/test_security_http_base_optional.py @@ -37,7 +37,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_basic_optional.py b/tests/test_security_http_basic_optional.py index 7e7fcac32..9b6cb6c45 100644 --- a/tests/test_security_http_basic_optional.py +++ b/tests/test_security_http_basic_optional.py @@ -54,7 +54,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_basic_realm.py b/tests/test_security_http_basic_realm.py index 470afd662..9fc33971a 100644 --- a/tests/test_security_http_basic_realm.py +++ b/tests/test_security_http_basic_realm.py @@ -52,7 +52,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_basic_realm_description.py b/tests/test_security_http_basic_realm_description.py index 44289007b..02122442e 100644 --- a/tests/test_security_http_basic_realm_description.py +++ b/tests/test_security_http_basic_realm_description.py @@ -52,7 +52,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_bearer.py b/tests/test_security_http_bearer.py index f24869fc3..5b9e2d691 100644 --- a/tests/test_security_http_bearer.py +++ b/tests/test_security_http_bearer.py @@ -37,7 +37,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_bearer_description.py b/tests/test_security_http_bearer_description.py index 6d5ad0b8e..2f11c3a14 100644 --- a/tests/test_security_http_bearer_description.py +++ b/tests/test_security_http_bearer_description.py @@ -37,7 +37,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_bearer_optional.py b/tests/test_security_http_bearer_optional.py index b596ac730..943da2ee2 100644 --- a/tests/test_security_http_bearer_optional.py +++ b/tests/test_security_http_bearer_optional.py @@ -43,7 +43,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_digest.py b/tests/test_security_http_digest.py index 2a25efe02..133d35763 100644 --- a/tests/test_security_http_digest.py +++ b/tests/test_security_http_digest.py @@ -39,7 +39,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_digest_description.py b/tests/test_security_http_digest_description.py index 721f7cfde..4e31a0c00 100644 --- a/tests/test_security_http_digest_description.py +++ b/tests/test_security_http_digest_description.py @@ -39,7 +39,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_http_digest_optional.py b/tests/test_security_http_digest_optional.py index d4c3597bc..1e6eb8bd7 100644 --- a/tests/test_security_http_digest_optional.py +++ b/tests/test_security_http_digest_optional.py @@ -45,7 +45,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_oauth2.py b/tests/test_security_oauth2.py index 23dce7cfa..73d1b7d94 100644 --- a/tests/test_security_oauth2.py +++ b/tests/test_security_oauth2.py @@ -135,7 +135,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login": { diff --git a/tests/test_security_oauth2_authorization_code_bearer.py b/tests/test_security_oauth2_authorization_code_bearer.py index 6df81528d..f2097b149 100644 --- a/tests/test_security_oauth2_authorization_code_bearer.py +++ b/tests/test_security_oauth2_authorization_code_bearer.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_security_oauth2_authorization_code_bearer_description.py b/tests/test_security_oauth2_authorization_code_bearer_description.py index c119abde4..5386fbbd9 100644 --- a/tests/test_security_oauth2_authorization_code_bearer_description.py +++ b/tests/test_security_oauth2_authorization_code_bearer_description.py @@ -44,7 +44,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_security_oauth2_optional.py b/tests/test_security_oauth2_optional.py index 3ef9f4a8d..b24c1b58f 100644 --- a/tests/test_security_oauth2_optional.py +++ b/tests/test_security_oauth2_optional.py @@ -139,7 +139,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login": { diff --git a/tests/test_security_oauth2_optional_description.py b/tests/test_security_oauth2_optional_description.py index b6425fde4..cda635151 100644 --- a/tests/test_security_oauth2_optional_description.py +++ b/tests/test_security_oauth2_optional_description.py @@ -140,7 +140,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login": { diff --git a/tests/test_security_oauth2_password_bearer_optional.py b/tests/test_security_oauth2_password_bearer_optional.py index e5dcbb553..4c9362c3e 100644 --- a/tests/test_security_oauth2_password_bearer_optional.py +++ b/tests/test_security_oauth2_password_bearer_optional.py @@ -41,7 +41,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_security_oauth2_password_bearer_optional_description.py b/tests/test_security_oauth2_password_bearer_optional_description.py index 9ff48e715..6e6ea846c 100644 --- a/tests/test_security_oauth2_password_bearer_optional_description.py +++ b/tests/test_security_oauth2_password_bearer_optional_description.py @@ -45,7 +45,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_security_openid_connect.py b/tests/test_security_openid_connect.py index 206de6574..1e322e640 100644 --- a/tests/test_security_openid_connect.py +++ b/tests/test_security_openid_connect.py @@ -47,7 +47,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_openid_connect_description.py b/tests/test_security_openid_connect_description.py index 5884de793..44cf57f86 100644 --- a/tests/test_security_openid_connect_description.py +++ b/tests/test_security_openid_connect_description.py @@ -49,7 +49,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_security_openid_connect_optional.py b/tests/test_security_openid_connect_optional.py index 8ac719118..e817434b0 100644 --- a/tests/test_security_openid_connect_optional.py +++ b/tests/test_security_openid_connect_optional.py @@ -53,7 +53,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_starlette_exception.py b/tests/test_starlette_exception.py index 96f835b93..229fe8016 100644 --- a/tests/test_starlette_exception.py +++ b/tests/test_starlette_exception.py @@ -80,7 +80,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/http-no-body-statuscode-exception": { diff --git a/tests/test_sub_callbacks.py b/tests/test_sub_callbacks.py index c5a0237e8..dce3ea5e2 100644 --- a/tests/test_sub_callbacks.py +++ b/tests/test_sub_callbacks.py @@ -87,7 +87,7 @@ def test_openapi_schema(): with client: response = client.get("/openapi.json") assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/invoices/": { diff --git a/tests/test_tuples.py b/tests/test_tuples.py index 4fa1f7a13..c37a25ca6 100644 --- a/tests/test_tuples.py +++ b/tests/test_tuples.py @@ -86,7 +86,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/model-with-tuple/": { diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py index 3d6267023..3afeaff84 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py index 6182ed507..8e084e152 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py @@ -27,7 +27,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py index 77568d9d4..bd34d2938 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py index 3fbd91e5c..5fc8b81ca 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py @@ -27,7 +27,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py index 3da362a50..8126cdcc6 100644 --- a/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_async_sql_databases/test_tutorial001.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/notes/": { diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py index 7533a1b68..a070f850f 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py @@ -15,7 +15,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/app": { diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py index 930ab3bf5..ce791e215 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py @@ -15,7 +15,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/app": { diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py index ae8f1a495..0ae9f4f93 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py @@ -15,7 +15,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "servers": [ {"url": "/api/v1"}, diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py index e67ad1cb1..576a411a4 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py @@ -15,7 +15,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "servers": [ {"url": "https://stag.example.com", "description": "Staging environment"}, diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index a13decd75..7da663435 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -166,7 +166,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an.py b/tests/test_tutorial/test_bigger_applications/test_main_an.py index 64e19c3f3..8f42d9dd1 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main_an.py +++ b/tests/test_tutorial/test_bigger_applications/test_main_an.py @@ -166,7 +166,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py index 70c86b4d7..44694e371 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py +++ b/tests/test_tutorial/test_bigger_applications/test_main_an_py39.py @@ -181,7 +181,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index cd1209ade..469198e0f 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -200,7 +200,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_body/test_tutorial001_py310.py b/tests/test_tutorial/test_body/test_tutorial001_py310.py index 5ebcbbf57..a68b4e044 100644 --- a/tests/test_tutorial/test_body/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body/test_tutorial001_py310.py @@ -215,7 +215,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py index a7ea0e949..4999cbf6b 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py @@ -64,7 +64,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py index 32f996ecb..011946d07 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001_an.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an.py @@ -64,7 +64,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py index 20e032fcd..e7dcb54e9 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py index e3baf5f2b..f1015a03b 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py index 4c2f48674..29c8ef4e9 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001_py310.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py index 496ab38fb..ce41a4283 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py @@ -50,7 +50,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py index 74a8a9b2e..acc4cfadc 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py @@ -50,7 +50,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py index 9c764b6d1..a8dc02a6c 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py @@ -58,7 +58,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py index 0cca29433..f31fee78e 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py @@ -58,7 +58,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py index 3b61e717e..0e46df253 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py @@ -58,7 +58,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py index b34377a28..8555cf88c 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py @@ -90,7 +90,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py index 9b8d5e15b..f4d300cc5 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py @@ -90,7 +90,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py index f8af555fc..afe2b2c20 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py @@ -98,7 +98,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py index 06e2c3146..033d5892e 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py @@ -98,7 +98,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py index 82c5fb101..8fcc00013 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py @@ -98,7 +98,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py index 378c24197..ac39cd93f 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/index-weights/": { diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py index 5ca63a92b..0800abe29 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py @@ -41,7 +41,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/index-weights/": { diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index 939bf44e0..151b4b917 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -34,7 +34,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py index 5f50f2071..c4b4b9df3 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py310.py @@ -44,7 +44,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py index d4fdabce6..940b4b3b8 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001_py39.py @@ -44,7 +44,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py index c1d8fd805..a43394ab1 100644 --- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py @@ -33,7 +33,7 @@ def test_default_openapi(): assert response.status_code == 200, response.text response = client.get("/openapi.json") assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py index c3511d129..902bed843 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py index f4f94c09d..aa5807844 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py index a80f10f81..ffb55d4e1 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py @@ -36,7 +36,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py index 1be898c09..9bc38effd 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py @@ -36,7 +36,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py index 7ba542c90..bb2953ef6 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py @@ -36,7 +36,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001.py b/tests/test_tutorial/test_custom_response/test_tutorial001.py index da2ca8d62..fc8362467 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001b.py b/tests/test_tutorial/test_custom_response/test_tutorial001b.py index f681f5a9d..91e5c501e 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001b.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial004.py b/tests/test_tutorial/test_custom_response/test_tutorial004.py index ef0ba3446..de60574f5 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial004.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial004.py @@ -27,7 +27,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial005.py b/tests/test_tutorial/test_custom_response/test_tutorial005.py index e4b5c1546..889bf3e92 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial005.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial005.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py index 9f1b07bee..2d0a2cd3f 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/typer": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py index cf204cbc0..1739fd457 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/fastapi": { diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py index f196899ac..51aa1833d 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/pydantic": { diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py index 26ae04c51..e20c0efe9 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py @@ -34,7 +34,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py index 675e826b1..e122239d8 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py @@ -22,7 +22,7 @@ def test_openapi_schema(): assert response.status_code == 200 data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/next": { diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index f3378fe62..204426e8b 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -55,7 +55,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/authors/{author_id}/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py index 974b9304f..a8e564ebe 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py @@ -26,7 +26,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an.py index b1ca27ff8..4e6a329f4 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_an.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an.py @@ -26,7 +26,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py index 70bed03f6..205aee908 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py index 9c5723be8..73593ea55 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py index 1bcde4e9f..10bf84fb5 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001_py310.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial004.py index 298bc290d..d16fd9ef7 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004.py @@ -64,7 +64,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an.py index f985be8df..46fe97fb2 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004_an.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an.py @@ -64,7 +64,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py index fc0286702..c6a0fc665 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py index 1e37673ed..30431cd29 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py index ab936ccdc..9793c8c33 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004_py310.py @@ -72,7 +72,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py index 2e9c82d71..6fac9f8eb 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py @@ -54,7 +54,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py index 919066dca..810537e48 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006_an.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an.py @@ -54,7 +54,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py index c23718479..f17cbcfc7 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py @@ -66,7 +66,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py index b92b96c01..af1fcde55 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py @@ -99,7 +99,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py index 2ddb7bb53..c33d51d87 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012_an.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an.py @@ -99,7 +99,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py index 595c83a53..d7bd756b5 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py @@ -115,7 +115,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py index 52f9beed5..a5bb299ac 100644 --- a/tests/test_tutorial/test_events/test_tutorial001.py +++ b/tests/test_tutorial/test_events/test_tutorial001.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py index 882d41aa5..81cbf4ab6 100644 --- a/tests/test_tutorial/test_events/test_tutorial002.py +++ b/tests/test_tutorial/test_events/test_tutorial002.py @@ -17,7 +17,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_events/test_tutorial003.py b/tests/test_tutorial/test_events/test_tutorial003.py index b2820b63c..0ad1a1f8b 100644 --- a/tests/test_tutorial/test_events/test_tutorial003.py +++ b/tests/test_tutorial/test_events/test_tutorial003.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/predict": { diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py index 6e71bb2de..a85a31350 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py @@ -15,11 +15,12 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "Custom title", + "summary": "This is a very custom OpenAPI schema", + "description": "Here's a longer description of the custom **OpenAPI** schema", "version": "2.5.0", - "description": "This is a very custom OpenAPI schema", "x-logo": { "url": "https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" }, diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py index 07a834990..39d2005ab 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py index 76836d447..3e497a291 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py @@ -30,7 +30,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py index 158ee01b3..b539cf3d6 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py @@ -39,7 +39,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py index 5be6452ee..efd31e63d 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py @@ -39,7 +39,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py index 5413fe428..733d9f406 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py @@ -39,7 +39,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py index f08bf4c50..21192b7db 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py @@ -28,7 +28,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py index 407c71787..c17ddbbe1 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003_py310.py @@ -38,7 +38,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py index 47790ba8f..71f6a8c70 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial004.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py @@ -18,7 +18,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py index a98700172..5475b92e1 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial004_py39.py @@ -27,7 +27,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py index 7c094b253..b0861c37f 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/keyword-weights/": { diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py index b40386450..7278e93c3 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005_py39.py @@ -24,7 +24,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/keyword-weights/": { diff --git a/tests/test_tutorial/test_first_steps/test_tutorial001.py b/tests/test_tutorial/test_first_steps/test_tutorial001.py index ea37aec53..6cc9fc228 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial001.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial001.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py index 8b22eab9e..1cd9678a1 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py @@ -32,7 +32,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py index 99a1053ca..8809c135b 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py index 091c74f4d..efd86ebde 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items-header/{item_id}": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py index 1639cb1d8..4763f68f3 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/unicorns/{name}": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py index 246f3b94c..0c0988c64 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py @@ -32,7 +32,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py index af47fd1a4..f356178ac 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py index 4a39bd102..4dd1adf43 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py @@ -35,7 +35,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py index 80f502d6a..030159dcf 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001.py @@ -24,7 +24,7 @@ def test_openapi(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_an.py b/tests/test_tutorial/test_header_params/test_tutorial001_an.py index f0ad7b816..3755ab758 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001_an.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001_an.py @@ -24,7 +24,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py index d095c7123..207b3b02b 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py @@ -32,7 +32,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py index bf176bba2..bf51982b7 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001_py310.py @@ -32,7 +32,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial002.py b/tests/test_tutorial/test_header_params/test_tutorial002.py index 516abda8b..545fc836b 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002.py @@ -35,7 +35,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an.py b/tests/test_tutorial/test_header_params/test_tutorial002_an.py index 97493e604..cfd581e33 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002_an.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002_an.py @@ -35,7 +35,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py index e0c60342a..c8d61e42e 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py @@ -43,7 +43,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py b/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py index c1bc5faf8..85150d4a9 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py @@ -46,7 +46,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial002_py310.py b/tests/test_tutorial/test_header_params/test_tutorial002_py310.py index 81871b8c6..f189d85b5 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002_py310.py @@ -46,7 +46,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial003.py b/tests/test_tutorial/test_header_params/test_tutorial003.py index 99dd9e25f..b2fc17b8f 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003.py @@ -26,7 +26,7 @@ def test_openapi_schema(): assert response.status_code == 200 # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an.py b/tests/test_tutorial/test_header_params/test_tutorial003_an.py index 4477da7a8..87fa839e2 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003_an.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003_an.py @@ -26,7 +26,7 @@ def test_openapi_schema(): assert response.status_code == 200 # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py b/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py index b52304a2b..ef6c268c5 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): assert response.status_code == 200 # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py b/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py index dffdd1622..6525fd50c 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): assert response.status_code == 200 # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_header_params/test_tutorial003_py310.py b/tests/test_tutorial/test_header_params/test_tutorial003_py310.py index 64ef7b22a..b404ce5d8 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003_py310.py @@ -34,7 +34,7 @@ def test_openapi_schema(client: TestClient): assert response.status_code == 200 # insert_assert(response.json()) assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py index f1ddc3259..04e8ff82b 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001.py @@ -15,9 +15,10 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": { "title": "ChimichangApp", + "summary": "Deadpool's favorite app. Nuff said.", "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n", "termsOfService": "http://example.com/terms/", "contact": { diff --git a/tests/test_tutorial/test_metadata/test_tutorial001_1.py b/tests/test_tutorial/test_metadata/test_tutorial001_1.py new file mode 100644 index 000000000..3efb1c432 --- /dev/null +++ b/tests/test_tutorial/test_metadata/test_tutorial001_1.py @@ -0,0 +1,49 @@ +from fastapi.testclient import TestClient + +from docs_src.metadata.tutorial001_1 import app + +client = TestClient(app) + + +def test_items(): + response = client.get("/items/") + assert response.status_code == 200, response.text + assert response.json() == [{"name": "Katana"}] + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": { + "title": "ChimichangApp", + "summary": "Deadpool's favorite app. Nuff said.", + "description": "\nChimichangApp API helps you do awesome stuff. 🚀\n\n## Items\n\nYou can **read items**.\n\n## Users\n\nYou will be able to:\n\n* **Create users** (_not implemented_).\n* **Read users** (_not implemented_).\n", + "termsOfService": "http://example.com/terms/", + "contact": { + "name": "Deadpoolio the Amazing", + "url": "http://x-force.example.com/contact/", + "email": "dp@x-force.example.com", + }, + "license": { + "name": "Apache 2.0", + "identifier": "MIT", + }, + "version": "0.0.1", + }, + "paths": { + "/items/": { + "get": { + "summary": "Read Items", + "operationId": "read_items_items__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, + } diff --git a/tests/test_tutorial/test_metadata/test_tutorial004.py b/tests/test_tutorial/test_metadata/test_tutorial004.py index f7f47a558..507220371 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial004.py +++ b/tests/test_tutorial/test_metadata/test_tutorial004.py @@ -16,7 +16,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py index c6cdc6064..a6e898c49 100644 --- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/invoices/": { diff --git a/tests/test_tutorial/test_openapi_webhooks/__init__.py b/tests/test_tutorial/test_openapi_webhooks/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py new file mode 100644 index 000000000..9111fdb2f --- /dev/null +++ b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py @@ -0,0 +1,117 @@ +from fastapi.testclient import TestClient + +from docs_src.openapi_webhooks.tutorial001 import app + +client = TestClient(app) + + +def test_get(): + response = client.get("/users/") + assert response.status_code == 200, response.text + assert response.json() == ["Rick", "Morty"] + + +def test_dummy_webhook(): + # Just for coverage + app.webhooks.routes[0].endpoint({}) + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/users/": { + "get": { + "summary": "Read Users", + "operationId": "read_users_users__get", + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + } + }, + } + } + }, + "webhooks": { + "new-subscription": { + "post": { + "summary": "New Subscription", + "description": "When a new user subscribes to your service we'll send you a POST request with this\ndata to the URL that you register for the event `new-subscription` in the dashboard.", + "operationId": "new_subscriptionnew_subscription_post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Subscription"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Subscription": { + "properties": { + "username": {"type": "string", "title": "Username"}, + "montly_fee": {"type": "number", "title": "Montly Fee"}, + "start_date": { + "type": "string", + "format": "date-time", + "title": "Start Date", + }, + }, + "type": "object", + "required": ["username", "montly_fee", "start_date"], + "title": "Subscription", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py index c1cdbee24..95542398e 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py index fdaddd018..d1388c367 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py index 782c64a84..313bb2a04 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": {}, } diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index f5fd868eb..cd9fc520e 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py index 52379c01e..07e2d7d20 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py @@ -14,7 +14,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py index deb6b0910..f92c59015 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py @@ -22,7 +22,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py index 470956a77..3b88a38c2 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py @@ -56,7 +56,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py index 76e44b5e5..58dec5769 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index cf8e203a0..30278caf8 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py index 497fc9024..cf59d354c 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py @@ -30,7 +30,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py index 09fac44c4..a93ea8807 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py @@ -30,7 +30,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py index e90771f24..91180d109 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py @@ -24,7 +24,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py index ab0455bf5..acbeaca76 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial004.py +++ b/tests/test_tutorial/test_path_params/test_tutorial004.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/{file_path}": { diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index 3401f2253..b9b58c961 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -51,7 +51,7 @@ def test_openapi(): assert response.status_code == 200, response.text data = response.json() assert data == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/models/{model_name}": { diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py index 3c408449b..6c2cba7e1 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial005.py +++ b/tests/test_tutorial/test_query_params/test_tutorial005.py @@ -35,7 +35,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py index 7fe58a990..626637903 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006.py @@ -60,7 +60,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py index b90c0a6c8..b6fb2f39e 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006_py310.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006_py310.py @@ -67,7 +67,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200 assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py index c41f554ba..370ae0ff0 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py @@ -45,7 +45,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py index dc8028f81..1f76ef314 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py @@ -45,7 +45,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py index 496b95b79..3a06b4bc7 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py index 2005e5043..1e6f93093 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py index 8147d768e..63524d291 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py index d6d69c169..164ec1193 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py index 3a53d422e..2afaafd92 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py index f00df2879..fafd38337 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py index 895fb8e9f..f3fb47528 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py index 4f4b1fd55..21f348f2b 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py index d85bb6231..f2c2a5a33 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py index 7bc020540..1436db384 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py index be5557f6a..270763f1d 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py index d9512e193..548391683 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py index b2a2c8d1d..e7d745154 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py index 4a0b9e8b5..1ba1fdf61 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py index 71e4638ae..343261748 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py index 4e90db358..537d6325b 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py @@ -33,7 +33,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py index 7686c07b3..7bce7590c 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py index e739044a8..2182e87b7 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py index 73f0ba78b..344004d01 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py @@ -31,7 +31,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py index e2c149992..5d4f6df3d 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py @@ -31,7 +31,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py index 07f30b739..dad49fb12 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py @@ -31,7 +31,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index 3269801ef..84c736180 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -66,7 +66,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py index 4b6edfa06..8ebe4eafd 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py @@ -43,7 +43,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py index 0c34620e3..5da8b320b 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an.py @@ -43,7 +43,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py index 04442c76f..166f59b1a 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py index f5249ef5b..02ea604b2 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py index f690d107b..c753e14d1 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py @@ -55,7 +55,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py index 4af659a11..f02170814 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py index 91dbc60b9..acfb749ce 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03_an.py @@ -31,7 +31,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py index 7c4ad326c..36e5faac1 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py @@ -39,7 +39,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an.py b/tests/test_tutorial/test_request_files/test_tutorial001_an.py index 80c288ed6..6eb2d55dc 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_an.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_an.py @@ -66,7 +66,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py index 4dc1f752c..4e3ef6869 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py @@ -76,7 +76,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 6868be328..65a8a9e61 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -77,7 +77,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_an.py b/tests/test_tutorial/test_request_files/test_tutorial002_an.py index ca1f62ea3..52a8e1964 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002_an.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002_an.py @@ -77,7 +77,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py index e593ae75d..6594e0116 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py @@ -96,7 +96,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py index bacd25b97..bfe964604 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002_py39.py @@ -96,7 +96,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py index e2d69184b..85cd03a59 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003.py @@ -54,7 +54,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial003_an.py b/tests/test_tutorial/test_request_files/test_tutorial003_an.py index f199d4d2f..0327a2db6 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003_an.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003_an.py @@ -54,7 +54,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial003_an_py39.py b/tests/test_tutorial/test_request_files/test_tutorial003_an_py39.py index 51fa83470..3aa68c621 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003_an_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003_an_py39.py @@ -82,7 +82,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py index 32b028909..238bb39cd 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003_py39.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003_py39.py @@ -82,7 +82,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py index 721c97fb1..4a2a7abe9 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py @@ -70,7 +70,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login/": { diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001_an.py b/tests/test_tutorial/test_request_forms/test_tutorial001_an.py index 6b8abab19..347361344 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001_an.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001_an.py @@ -70,7 +70,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login/": { diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py index 5862524ad..e65a8823e 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py @@ -81,7 +81,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/login/": { diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index dcc44cf09..be12656d2 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -112,7 +112,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py index f11e36984..a5fcb3a94 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py @@ -112,7 +112,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py index 9b5e8681c..6eacb2fcf 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py @@ -131,7 +131,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/files/": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py index 4a95cb2b5..9cb0419a3 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003.py @@ -27,7 +27,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/user/": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01.py b/tests/test_tutorial/test_response_model/test_tutorial003_01.py index a055bc688..8b8fe514a 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_01.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_01.py @@ -27,7 +27,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/user/": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py index 8cb4ac208..01dc8e71c 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py @@ -36,7 +36,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/user/": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_02.py b/tests/test_tutorial/test_response_model/test_tutorial003_02.py index 6ccb054b8..eabd20345 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_02.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_02.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/portal": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_03.py b/tests/test_tutorial/test_response_model/test_tutorial003_03.py index ba4c0f275..970ff5845 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_03.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_03.py @@ -15,7 +15,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/teleport": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_05.py b/tests/test_tutorial/test_response_model/test_tutorial003_05.py index d7c232e75..c7a39cc74 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_05.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_05.py @@ -21,7 +21,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/portal": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_05_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_05_py310.py index a89f1dad8..f80d62572 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_05_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_05_py310.py @@ -31,7 +31,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/portal": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py index 1f4ec9057..602147b13 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_py310.py @@ -36,7 +36,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/user/": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py index 8cb7dc9cf..07af29207 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004.py @@ -36,7 +36,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py index 2ba8143ba..90147fbdd 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004_py310.py @@ -44,7 +44,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py index 97df0a238..740a49590 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004_py39.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004_py39.py @@ -44,7 +44,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py index 76662f793..e8c8946c5 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005.py @@ -25,7 +25,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}/name": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py index 1b1cf4175..388e030bd 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005_py310.py @@ -35,7 +35,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}/name": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py index 3a759fde4..548a3dbd8 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006.py @@ -25,7 +25,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}/name": { diff --git a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py index 07e84cc82..075bb8079 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006_py310.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006_py310.py @@ -35,7 +35,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}/name": { diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py index 784517d69..dea136fb2 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { @@ -41,31 +41,34 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", + { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, }, - }, - }, + { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + ], + } } }, "required": True, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py index 222a4edfe..571feb19f 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py @@ -23,7 +23,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { @@ -41,31 +41,34 @@ def test_openapi_schema(): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", + { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, }, - }, - }, + { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + ], + } } }, "required": True, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py index 1eacd640a..e25531794 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py @@ -32,7 +32,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { @@ -50,31 +50,34 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", + { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, }, - }, - }, + { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + ], + } } }, "required": True, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py index 632f2cbe0..dafc5afad 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py @@ -32,7 +32,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { @@ -50,31 +50,34 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", + { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, }, - }, - }, + { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + ], + } } }, "required": True, diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py index c99cb75c8..29004218b 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py @@ -32,7 +32,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/{item_id}": { @@ -50,31 +50,34 @@ def test_openapi_schema(client: TestClient): "requestBody": { "content": { "application/json": { - "schema": {"$ref": "#/components/schemas/Item"}, - "examples": { - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, + "schema": { + "allOf": [{"$ref": "#/components/schemas/Item"}], + "title": "Item", + "examples": [ + { + "summary": "A normal example", + "description": "A **normal** item works correctly.", + "value": { + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, + }, }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", + { + "summary": "An example with converted data", + "description": "FastAPI can convert price `strings` to actual `numbers` automatically", + "value": {"name": "Bar", "price": "35.4"}, }, - }, - }, + { + "summary": "Invalid data is rejected with an error", + "value": { + "name": "Baz", + "price": "thirty five point four", + }, + }, + ], + } } }, "required": True, diff --git a/tests/test_tutorial/test_security/test_tutorial001.py b/tests/test_tutorial/test_security/test_tutorial001.py index a7f55b78b..417bed8f7 100644 --- a/tests/test_tutorial/test_security/test_tutorial001.py +++ b/tests/test_tutorial/test_security/test_tutorial001.py @@ -29,7 +29,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_security/test_tutorial001_an.py b/tests/test_tutorial/test_security/test_tutorial001_an.py index fc48703aa..59460da7f 100644 --- a/tests/test_tutorial/test_security/test_tutorial001_an.py +++ b/tests/test_tutorial/test_security/test_tutorial001_an.py @@ -29,7 +29,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_security/test_tutorial001_an_py39.py b/tests/test_tutorial/test_security/test_tutorial001_an_py39.py index 345e0be0f..d8e712773 100644 --- a/tests/test_tutorial/test_security/test_tutorial001_an_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial001_an_py39.py @@ -40,7 +40,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index c10f928eb..cb5cdaa04 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -70,7 +70,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial003_an.py b/tests/test_tutorial/test_security/test_tutorial003_an.py index 41872fda0..26e68a029 100644 --- a/tests/test_tutorial/test_security/test_tutorial003_an.py +++ b/tests/test_tutorial/test_security/test_tutorial003_an.py @@ -70,7 +70,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial003_an_py310.py b/tests/test_tutorial/test_security/test_tutorial003_an_py310.py index 02bd748c8..1250d4afb 100644 --- a/tests/test_tutorial/test_security/test_tutorial003_an_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial003_an_py310.py @@ -86,7 +86,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial003_an_py39.py b/tests/test_tutorial/test_security/test_tutorial003_an_py39.py index 7e74afafb..b74cfdc54 100644 --- a/tests/test_tutorial/test_security/test_tutorial003_an_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial003_an_py39.py @@ -86,7 +86,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial003_py310.py b/tests/test_tutorial/test_security/test_tutorial003_py310.py index a463751f5..8a75d2321 100644 --- a/tests/test_tutorial/test_security/test_tutorial003_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial003_py310.py @@ -86,7 +86,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index ccb5b3c9f..4e4b6afe8 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -179,7 +179,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005_an.py b/tests/test_tutorial/test_security/test_tutorial005_an.py index e851f47fe..51cc8329a 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_an.py +++ b/tests/test_tutorial/test_security/test_tutorial005_an.py @@ -179,7 +179,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py index cca581980..b0d0fed12 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_an_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial005_an_py310.py @@ -207,7 +207,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py index eae851457..26deaaf3c 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_an_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial005_an_py39.py @@ -207,7 +207,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005_py310.py b/tests/test_tutorial/test_security/test_tutorial005_py310.py index cdbd8f75e..e93f34c3b 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_py310.py +++ b/tests/test_tutorial/test_security/test_tutorial005_py310.py @@ -207,7 +207,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial005_py39.py b/tests/test_tutorial/test_security/test_tutorial005_py39.py index 45b2a2341..737a8548f 100644 --- a/tests/test_tutorial/test_security/test_tutorial005_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial005_py39.py @@ -207,7 +207,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/token": { diff --git a/tests/test_tutorial/test_security/test_tutorial006.py b/tests/test_tutorial/test_security/test_tutorial006.py index 73cbdc538..dc459b6fd 100644 --- a/tests/test_tutorial/test_security/test_tutorial006.py +++ b/tests/test_tutorial/test_security/test_tutorial006.py @@ -42,7 +42,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_tutorial/test_security/test_tutorial006_an.py b/tests/test_tutorial/test_security/test_tutorial006_an.py index 5f970ed01..52ddd938f 100644 --- a/tests/test_tutorial/test_security/test_tutorial006_an.py +++ b/tests/test_tutorial/test_security/test_tutorial006_an.py @@ -42,7 +42,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_tutorial/test_security/test_tutorial006_an_py39.py b/tests/test_tutorial/test_security/test_tutorial006_an_py39.py index 7d7a851ac..52b22e573 100644 --- a/tests/test_tutorial/test_security/test_tutorial006_an_py39.py +++ b/tests/test_tutorial/test_security/test_tutorial006_an_py39.py @@ -54,7 +54,7 @@ def test_openapi_schema(client: TestClient): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/me": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases.py b/tests/test_tutorial/test_sql_databases/test_sql_databases.py index a2628f3c3..d927940da 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases.py @@ -89,7 +89,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py index 02501b1a2..08d7b3533 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py @@ -91,7 +91,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py index 67b92ea4a..493fb3b6b 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py @@ -105,7 +105,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py index a2af20ea2..7b56685bc 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py @@ -105,7 +105,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py index 2f918cfd8..43c2b272f 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py @@ -104,7 +104,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py index f2eefe41d..fd33517db 100644 --- a/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py +++ b/tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py @@ -104,7 +104,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py index d2470a2db..ac6c427ca 100644 --- a/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py +++ b/tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py @@ -97,7 +97,7 @@ def test_openapi_schema(client): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/users/": { diff --git a/tests/test_tutorial/test_sub_applications/test_tutorial001.py b/tests/test_tutorial/test_sub_applications/test_tutorial001.py index 00e9aec57..0790d207b 100644 --- a/tests/test_tutorial/test_sub_applications/test_tutorial001.py +++ b/tests/test_tutorial/test_sub_applications/test_tutorial001.py @@ -5,7 +5,7 @@ from docs_src.sub_applications.tutorial001 import app client = TestClient(app) openapi_schema_main = { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/app": { @@ -23,7 +23,7 @@ openapi_schema_main = { }, } openapi_schema_sub = { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/sub": { diff --git a/tests/test_tutorial/test_testing/test_main.py b/tests/test_tutorial/test_testing/test_main.py index 937ce75e4..fe3498081 100644 --- a/tests/test_tutorial/test_testing/test_main.py +++ b/tests/test_tutorial/test_testing/test_main.py @@ -9,7 +9,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_tutorial/test_testing/test_tutorial001.py b/tests/test_tutorial/test_testing/test_tutorial001.py index f3db70af2..471e896c9 100644 --- a/tests/test_tutorial/test_testing/test_tutorial001.py +++ b/tests/test_tutorial/test_testing/test_tutorial001.py @@ -9,7 +9,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/": { diff --git a/tests/test_union_body.py b/tests/test_union_body.py index bc1e74432..57a14b574 100644 --- a/tests/test_union_body.py +++ b/tests/test_union_body.py @@ -39,7 +39,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_union_inherited_body.py b/tests/test_union_inherited_body.py index 988b920aa..c2a37d3dd 100644 --- a/tests/test_union_inherited_body.py +++ b/tests/test_union_inherited_body.py @@ -39,7 +39,7 @@ def test_openapi_schema(): response = client.get("/openapi.json") assert response.status_code == 200, response.text assert response.json() == { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items/": { diff --git a/tests/test_webhooks_security.py b/tests/test_webhooks_security.py new file mode 100644 index 000000000..a1c7b18fb --- /dev/null +++ b/tests/test_webhooks_security.py @@ -0,0 +1,126 @@ +from datetime import datetime + +from fastapi import FastAPI, Security +from fastapi.security import HTTPBearer +from fastapi.testclient import TestClient +from pydantic import BaseModel +from typing_extensions import Annotated + +app = FastAPI() + +bearer_scheme = HTTPBearer() + + +class Subscription(BaseModel): + username: str + montly_fee: float + start_date: datetime + + +@app.webhooks.post("new-subscription") +def new_subscription( + body: Subscription, token: Annotated[str, Security(bearer_scheme)] +): + """ + When a new user subscribes to your service we'll send you a POST request with this + data to the URL that you register for the event `new-subscription` in the dashboard. + """ + + +client = TestClient(app) + + +def test_dummy_webhook(): + # Just for coverage + new_subscription(body={}, token="Bearer 123") + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + # insert_assert(response.json()) + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": {}, + "webhooks": { + "new-subscription": { + "post": { + "summary": "New Subscription", + "description": "When a new user subscribes to your service we'll send you a POST request with this\ndata to the URL that you register for the event `new-subscription` in the dashboard.", + "operationId": "new_subscriptionnew_subscription_post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Subscription"} + } + }, + "required": True, + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + "security": [{"HTTPBearer": []}], + } + } + }, + "components": { + "schemas": { + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "Subscription": { + "properties": { + "username": {"type": "string", "title": "Username"}, + "montly_fee": {"type": "number", "title": "Montly Fee"}, + "start_date": { + "type": "string", + "format": "date-time", + "title": "Start Date", + }, + }, + "type": "object", + "required": ["username", "montly_fee", "start_date"], + "title": "Subscription", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + }, + "securitySchemes": {"HTTPBearer": {"type": "http", "scheme": "bearer"}}, + }, + } From b757211299b19e2715513826c41b7f48da2e51eb Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 30 Jun 2023 18:25:53 +0000 Subject: [PATCH 06/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index fca7502cc..edf8ef13e 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* ✨ Add support for OpenAPI 3.1.0. PR [#9770](https://github.com/tiangolo/fastapi/pull/9770) by [@tiangolo](https://github.com/tiangolo). * 🔨 Enable linenums in MkDocs Material during local live development to simplify highlighting code. PR [#9769](https://github.com/tiangolo/fastapi/pull/9769) by [@tiangolo](https://github.com/tiangolo). * ✨ Add support for `deque` objects and children in `jsonable_encoder`. PR [#9433](https://github.com/tiangolo/fastapi/pull/9433) by [@cranium](https://github.com/cranium). * ⬆ Update httpx requirement from <0.24.0,>=0.23.0 to >=0.23.0,<0.25.0. PR [#9724](https://github.com/tiangolo/fastapi/pull/9724) by [@dependabot[bot]](https://github.com/apps/dependabot). From efc2bcc57ac6a711a835f55159252c220db74213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 30 Jun 2023 20:54:25 +0200 Subject: [PATCH 07/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index edf8ef13e..18abf0ee4 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,16 +2,32 @@ ## Latest Changes +### Features + * ✨ Add support for OpenAPI 3.1.0. PR [#9770](https://github.com/tiangolo/fastapi/pull/9770) by [@tiangolo](https://github.com/tiangolo). -* 🔨 Enable linenums in MkDocs Material during local live development to simplify highlighting code. PR [#9769](https://github.com/tiangolo/fastapi/pull/9769) by [@tiangolo](https://github.com/tiangolo). + * New support for documenting **webhooks**, read the new docs here: Advanced User Guide: OpenAPI Webhooks. + * Upgrade OpenAPI 3.1.0, this uses JSON Schema 2020-12. + * Upgrade Swagger UI to version 5.x.x, that supports OpenAPI 3.1.0. + * Updated `examples` field in `Query()`, `Cookie()`, `Body()`, etc. based on the latest JSON Schema and OpenAPI. Now it takes a list of examples and they are included directly in the JSON Schema, not outside. Read more about it (including the historical technical details) in the updated docs: Tutorial: Declare Request Example Data. + * ✨ Add support for `deque` objects and children in `jsonable_encoder`. PR [#9433](https://github.com/tiangolo/fastapi/pull/9433) by [@cranium](https://github.com/cranium). + +### Docs + +* 📝 Fix form for the FastAPI and friends newsletter. PR [#9749](https://github.com/tiangolo/fastapi/pull/9749) by [@tiangolo](https://github.com/tiangolo). + +### Translations + +* 🌐 Add Persian translation for `docs/fa/docs/advanced/sub-applications.md`. PR [#9692](https://github.com/tiangolo/fastapi/pull/9692) by [@mojtabapaso](https://github.com/mojtabapaso). +* 🌐 Add Russian translation for `docs/ru/docs/tutorial/response-model.md`. PR [#9675](https://github.com/tiangolo/fastapi/pull/9675) by [@glsglsgls](https://github.com/glsglsgls). + +### Internal + +* 🔨 Enable linenums in MkDocs Material during local live development to simplify highlighting code. PR [#9769](https://github.com/tiangolo/fastapi/pull/9769) by [@tiangolo](https://github.com/tiangolo). * ⬆ Update httpx requirement from <0.24.0,>=0.23.0 to >=0.23.0,<0.25.0. PR [#9724](https://github.com/tiangolo/fastapi/pull/9724) by [@dependabot[bot]](https://github.com/apps/dependabot). * ⬆ Bump mkdocs-material from 9.1.16 to 9.1.17. PR [#9746](https://github.com/tiangolo/fastapi/pull/9746) by [@dependabot[bot]](https://github.com/apps/dependabot). * 🔥 Remove missing translation dummy pages, no longer necessary. PR [#9751](https://github.com/tiangolo/fastapi/pull/9751) by [@tiangolo](https://github.com/tiangolo). * ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#9259](https://github.com/tiangolo/fastapi/pull/9259) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci). -* 🌐 Add Persian translation for `docs/fa/docs/advanced/sub-applications.md`. PR [#9692](https://github.com/tiangolo/fastapi/pull/9692) by [@mojtabapaso](https://github.com/mojtabapaso). -* 🌐 Add Russian translation for `docs/ru/docs/tutorial/response-model.md`. PR [#9675](https://github.com/tiangolo/fastapi/pull/9675) by [@glsglsgls](https://github.com/glsglsgls). -* 📝 Fix form for the FastAPI and friends newsletter. PR [#9749](https://github.com/tiangolo/fastapi/pull/9749) by [@tiangolo](https://github.com/tiangolo). * ✨ Add Material for MkDocs Insiders features and cards. PR [#9748](https://github.com/tiangolo/fastapi/pull/9748) by [@tiangolo](https://github.com/tiangolo). * 🔥 Remove languages without translations. PR [#9743](https://github.com/tiangolo/fastapi/pull/9743) by [@tiangolo](https://github.com/tiangolo). * ✨ Refactor docs for building scripts, use MkDocs hooks, simplify (remove) configs for languages. PR [#9742](https://github.com/tiangolo/fastapi/pull/9742) by [@tiangolo](https://github.com/tiangolo). From 983f1d34dbc9443fcd12159647aabdeabc5032a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 30 Jun 2023 20:55:17 +0200 Subject: [PATCH 08/14] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.99.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 3 +++ fastapi/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 18abf0ee4..b68bd5f00 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,9 @@ ## Latest Changes + +## 0.99.0 + ### Features * ✨ Add support for OpenAPI 3.1.0. PR [#9770](https://github.com/tiangolo/fastapi/pull/9770) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 038e1ba86..9c4316e69 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.98.0" +__version__ = "0.99.0" from starlette import status as status From 4d83f984cc42831e3883285e9bedc4d69f4c1ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 1 Jul 2023 18:43:29 +0200 Subject: [PATCH 09/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20source=20examples?= =?UTF-8?q?=20to=20use=20new=20JSON=20Schema=20examples=20field=20(#9776)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📝 Update source examples to use new JSON Schema examples field * ✅ Update tests for JSON Schema examples * 📝 Update highlights in JSON Schema examples --- docs/en/docs/tutorial/schema-extra-example.md | 10 +++---- docs_src/schema_extra_example/tutorial004.py | 27 ++++++------------- .../schema_extra_example/tutorial004_an.py | 27 ++++++------------- .../tutorial004_an_py310.py | 27 ++++++------------- .../tutorial004_an_py39.py | 27 ++++++------------- .../schema_extra_example/tutorial004_py310.py | 27 ++++++------------- .../test_tutorial004.py | 25 +++++------------ .../test_tutorial004_an.py | 25 +++++------------ .../test_tutorial004_an_py310.py | 25 +++++------------ .../test_tutorial004_an_py39.py | 25 +++++------------ .../test_tutorial004_py310.py | 25 +++++------------ 11 files changed, 80 insertions(+), 190 deletions(-) diff --git a/docs/en/docs/tutorial/schema-extra-example.md b/docs/en/docs/tutorial/schema-extra-example.md index 6cf8bf181..86ccb1f5a 100644 --- a/docs/en/docs/tutorial/schema-extra-example.md +++ b/docs/en/docs/tutorial/schema-extra-example.md @@ -116,19 +116,19 @@ You can of course also pass multiple `examples`: === "Python 3.10+" - ```Python hl_lines="23-49" + ```Python hl_lines="23-38" {!> ../../../docs_src/schema_extra_example/tutorial004_an_py310.py!} ``` === "Python 3.9+" - ```Python hl_lines="23-49" + ```Python hl_lines="23-38" {!> ../../../docs_src/schema_extra_example/tutorial004_an_py39.py!} ``` === "Python 3.6+" - ```Python hl_lines="24-50" + ```Python hl_lines="24-39" {!> ../../../docs_src/schema_extra_example/tutorial004_an.py!} ``` @@ -137,7 +137,7 @@ You can of course also pass multiple `examples`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="19-45" + ```Python hl_lines="19-34" {!> ../../../docs_src/schema_extra_example/tutorial004_py310.py!} ``` @@ -146,7 +146,7 @@ You can of course also pass multiple `examples`: !!! tip Prefer to use the `Annotated` version if possible. - ```Python hl_lines="21-47" + ```Python hl_lines="21-36" {!> ../../../docs_src/schema_extra_example/tutorial004.py!} ``` diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004.py index eb49293fd..75514a3e9 100644 --- a/docs_src/schema_extra_example/tutorial004.py +++ b/docs_src/schema_extra_example/tutorial004.py @@ -20,29 +20,18 @@ async def update_item( item: Item = Body( examples=[ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, + "name": "Bar", + "price": "35.4", }, { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], ), diff --git a/docs_src/schema_extra_example/tutorial004_an.py b/docs_src/schema_extra_example/tutorial004_an.py index 567ec4702..e817302a2 100644 --- a/docs_src/schema_extra_example/tutorial004_an.py +++ b/docs_src/schema_extra_example/tutorial004_an.py @@ -23,29 +23,18 @@ async def update_item( Body( examples=[ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, + "name": "Bar", + "price": "35.4", }, { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], ), diff --git a/docs_src/schema_extra_example/tutorial004_an_py310.py b/docs_src/schema_extra_example/tutorial004_an_py310.py index 026654835..650da3187 100644 --- a/docs_src/schema_extra_example/tutorial004_an_py310.py +++ b/docs_src/schema_extra_example/tutorial004_an_py310.py @@ -22,29 +22,18 @@ async def update_item( Body( examples=[ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, + "name": "Bar", + "price": "35.4", }, { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], ), diff --git a/docs_src/schema_extra_example/tutorial004_an_py39.py b/docs_src/schema_extra_example/tutorial004_an_py39.py index 06219ede8..dc5a8fe49 100644 --- a/docs_src/schema_extra_example/tutorial004_an_py39.py +++ b/docs_src/schema_extra_example/tutorial004_an_py39.py @@ -22,29 +22,18 @@ async def update_item( Body( examples=[ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, + "name": "Bar", + "price": "35.4", }, { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], ), diff --git a/docs_src/schema_extra_example/tutorial004_py310.py b/docs_src/schema_extra_example/tutorial004_py310.py index ef2b9d8cb..05996ac2a 100644 --- a/docs_src/schema_extra_example/tutorial004_py310.py +++ b/docs_src/schema_extra_example/tutorial004_py310.py @@ -18,29 +18,18 @@ async def update_item( item: Item = Body( examples=[ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, + "name": "Bar", + "price": "35.4", }, { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], ), diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py index dea136fb2..313cd51d6 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -46,26 +46,15 @@ def test_openapi_schema(): "title": "Item", "examples": [ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, + {"name": "Bar", "price": "35.4"}, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py index 571feb19f..353401b78 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py @@ -46,26 +46,15 @@ def test_openapi_schema(): "title": "Item", "examples": [ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, + {"name": "Bar", "price": "35.4"}, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py index e25531794..79f4e1e1e 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py @@ -55,26 +55,15 @@ def test_openapi_schema(client: TestClient): "title": "Item", "examples": [ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, + {"name": "Bar", "price": "35.4"}, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py index dafc5afad..1ee120705 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py @@ -55,26 +55,15 @@ def test_openapi_schema(client: TestClient): "title": "Item", "examples": [ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, + {"name": "Bar", "price": "35.4"}, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], } diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py index 29004218b..b77368400 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py @@ -55,26 +55,15 @@ def test_openapi_schema(client: TestClient): "title": "Item", "examples": [ { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, + "name": "Foo", + "description": "A very nice Item", + "price": 35.4, + "tax": 3.2, }, + {"name": "Bar", "price": "35.4"}, { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": {"name": "Bar", "price": "35.4"}, - }, - { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, + "name": "Baz", + "price": "thirty five point four", }, ], } From 0f105d90769bb2fe4c79ff0f571f33db803fb16f Mon Sep 17 00:00:00 2001 From: github-actions Date: Sat, 1 Jul 2023 16:44:12 +0000 Subject: [PATCH 10/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index b68bd5f00..983c0e218 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 📝 Update source examples to use new JSON Schema examples field. PR [#9776](https://github.com/tiangolo/fastapi/pull/9776) by [@tiangolo](https://github.com/tiangolo). ## 0.99.0 From 07e1dea467c9654ea771bfef23cb3bf9654feb01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 2 Jul 2023 17:58:23 +0200 Subject: [PATCH 11/14] =?UTF-8?q?=F0=9F=90=9B=20Fix=20JSON=20Schema=20acce?= =?UTF-8?q?pting=20bools=20as=20valid=20JSON=20Schemas,=20e.g.=20`addition?= =?UTF-8?q?alProperties:=20false`=20(#9781)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. additionalProperties: false * ✅ Add test to ensure additionalProperties can be false * ♻️ Tweak OpenAPI models to support Pydantic v1's JSON Schema for tuples --- fastapi/openapi/models.py | 46 +++++---- tests/test_additional_properties_bool.py | 115 +++++++++++++++++++++++ 2 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 tests/test_additional_properties_bool.py diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 7420d3b55..a2ea53607 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -114,27 +114,30 @@ class Schema(BaseModel): dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") ref: Optional[str] = Field(default=None, alias="$ref") dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") - defs: Optional[Dict[str, "Schema"]] = Field(default=None, alias="$defs") + defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") comment: Optional[str] = Field(default=None, alias="$comment") # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s # A Vocabulary for Applying Subschemas - allOf: Optional[List["Schema"]] = None - anyOf: Optional[List["Schema"]] = None - oneOf: Optional[List["Schema"]] = None - not_: Optional["Schema"] = Field(default=None, alias="not") - if_: Optional["Schema"] = Field(default=None, alias="if") - then: Optional["Schema"] = None - else_: Optional["Schema"] = Field(default=None, alias="else") - dependentSchemas: Optional[Dict[str, "Schema"]] = None - prefixItems: Optional[List["Schema"]] = None - items: Optional[Union["Schema", List["Schema"]]] = None - contains: Optional["Schema"] = None - properties: Optional[Dict[str, "Schema"]] = None - patternProperties: Optional[Dict[str, "Schema"]] = None - additionalProperties: Optional["Schema"] = None - propertyNames: Optional["Schema"] = None - unevaluatedItems: Optional["Schema"] = None - unevaluatedProperties: Optional["Schema"] = None + allOf: Optional[List["SchemaOrBool"]] = None + anyOf: Optional[List["SchemaOrBool"]] = None + oneOf: Optional[List["SchemaOrBool"]] = None + not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") + if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") + then: Optional["SchemaOrBool"] = None + else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") + dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None + prefixItems: Optional[List["SchemaOrBool"]] = None + # TODO: uncomment and remove below when deprecating Pydantic v1 + # It generales a list of schemas for tuples, before prefixItems was available + # items: Optional["SchemaOrBool"] = None + items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None + contains: Optional["SchemaOrBool"] = None + properties: Optional[Dict[str, "SchemaOrBool"]] = None + patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None + additionalProperties: Optional["SchemaOrBool"] = None + propertyNames: Optional["SchemaOrBool"] = None + unevaluatedItems: Optional["SchemaOrBool"] = None + unevaluatedProperties: Optional["SchemaOrBool"] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural # A Vocabulary for Structural Validation type: Optional[str] = None @@ -164,7 +167,7 @@ class Schema(BaseModel): # A Vocabulary for the Contents of String-Encoded Data contentEncoding: Optional[str] = None contentMediaType: Optional[str] = None - contentSchema: Optional["Schema"] = None + contentSchema: Optional["SchemaOrBool"] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-basic-meta # A Vocabulary for Basic Meta-Data Annotations title: Optional[str] = None @@ -191,6 +194,11 @@ class Schema(BaseModel): extra: str = "allow" +# Ref: https://json-schema.org/draft/2020-12/json-schema-core.html#name-json-schema-documents +# A JSON Schema MUST be an object or a boolean. +SchemaOrBool = Union[Schema, bool] + + class Example(BaseModel): summary: Optional[str] = None description: Optional[str] = None diff --git a/tests/test_additional_properties_bool.py b/tests/test_additional_properties_bool.py new file mode 100644 index 000000000..e35c26342 --- /dev/null +++ b/tests/test_additional_properties_bool.py @@ -0,0 +1,115 @@ +from typing import Union + +from fastapi import FastAPI +from fastapi.testclient import TestClient +from pydantic import BaseModel + + +class FooBaseModel(BaseModel): + class Config: + extra = "forbid" + + +class Foo(FooBaseModel): + pass + + +app = FastAPI() + + +@app.post("/") +async def post( + foo: Union[Foo, None] = None, +): + return foo + + +client = TestClient(app) + + +def test_call_invalid(): + response = client.post("/", json={"foo": {"bar": "baz"}}) + assert response.status_code == 422 + + +def test_call_valid(): + response = client.post("/", json={}) + assert response.status_code == 200 + assert response.json() == {} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == { + "openapi": "3.1.0", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/": { + "post": { + "summary": "Post", + "operationId": "post__post", + "requestBody": { + "content": { + "application/json": { + "schema": {"$ref": "#/components/schemas/Foo"} + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": {"application/json": {"schema": {}}}, + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + }, + }, + } + } + }, + "components": { + "schemas": { + "Foo": { + "properties": {}, + "additionalProperties": False, + "type": "object", + "title": "Foo", + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": {"$ref": "#/components/schemas/ValidationError"}, + "type": "array", + "title": "Detail", + } + }, + "type": "object", + "title": "HTTPValidationError", + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [{"type": "string"}, {"type": "integer"}] + }, + "type": "array", + "title": "Location", + }, + "msg": {"type": "string", "title": "Message"}, + "type": {"type": "string", "title": "Error Type"}, + }, + "type": "object", + "required": ["loc", "msg", "type"], + "title": "ValidationError", + }, + } + }, + } From 6bd4f5353154b53920c4f313d2b635107c696be5 Mon Sep 17 00:00:00 2001 From: github-actions Date: Sun, 2 Jul 2023 15:59:00 +0000 Subject: [PATCH 12/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 983c0e218..c13023ce3 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,6 +2,7 @@ ## Latest Changes +* 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. `additionalProperties: false`. PR [#9781](https://github.com/tiangolo/fastapi/pull/9781) by [@tiangolo](https://github.com/tiangolo). * 📝 Update source examples to use new JSON Schema examples field. PR [#9776](https://github.com/tiangolo/fastapi/pull/9776) by [@tiangolo](https://github.com/tiangolo). ## 0.99.0 From 8a198fc1ed2647f1047099e8b19864ec13040e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 2 Jul 2023 18:00:12 +0200 Subject: [PATCH 13/14] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/en/docs/release-notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index c13023ce3..f22146f4b 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -2,7 +2,15 @@ ## Latest Changes + +## 0.99.1 + +### Fixes + * 🐛 Fix JSON Schema accepting bools as valid JSON Schemas, e.g. `additionalProperties: false`. PR [#9781](https://github.com/tiangolo/fastapi/pull/9781) by [@tiangolo](https://github.com/tiangolo). + +### Docs + * 📝 Update source examples to use new JSON Schema examples field. PR [#9776](https://github.com/tiangolo/fastapi/pull/9776) by [@tiangolo](https://github.com/tiangolo). ## 0.99.0 From dd4e78ca7b09abdf0d4646fe4697316c021a8b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 2 Jul 2023 18:00:39 +0200 Subject: [PATCH 14/14] =?UTF-8?q?=F0=9F=94=96=20Release=20version=200.99.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/__init__.py b/fastapi/__init__.py index 9c4316e69..2d1bac2e1 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.99.0" +__version__ = "0.99.1" from starlette import status as status