]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
✨ Add support for OpenAPI 3.1.0 (#9770)
authorSebastián Ramírez <tiangolo@gmail.com>
Fri, 30 Jun 2023 18:25:16 +0000 (20:25 +0200)
committerGitHub <noreply@github.com>
Fri, 30 Jun 2023 18:25:16 +0000 (20:25 +0200)
* ✨ 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

335 files changed:
docs/en/docs/advanced/additional-responses.md
docs/en/docs/advanced/behind-a-proxy.md
docs/en/docs/advanced/extending-openapi.md
docs/en/docs/advanced/openapi-callbacks.md
docs/en/docs/advanced/openapi-webhooks.md [new file with mode: 0644]
docs/en/docs/advanced/path-operation-advanced-configuration.md
docs/en/docs/img/tutorial/metadata/image01.png
docs/en/docs/img/tutorial/openapi-webhooks/image01.png [new file with mode: 0644]
docs/en/docs/tutorial/first-steps.md
docs/en/docs/tutorial/metadata.md
docs/en/docs/tutorial/path-params.md
docs/en/docs/tutorial/schema-extra-example.md
docs/en/mkdocs.yml
docs_src/extending_openapi/tutorial001.py
docs_src/metadata/tutorial001.py
docs_src/metadata/tutorial001_1.py [new file with mode: 0644]
docs_src/openapi_webhooks/tutorial001.py [new file with mode: 0644]
docs_src/schema_extra_example/tutorial001.py
docs_src/schema_extra_example/tutorial001_py310.py
docs_src/schema_extra_example/tutorial002.py
docs_src/schema_extra_example/tutorial002_py310.py
docs_src/schema_extra_example/tutorial003.py
docs_src/schema_extra_example/tutorial003_an.py
docs_src/schema_extra_example/tutorial003_an_py310.py
docs_src/schema_extra_example/tutorial003_an_py39.py
docs_src/schema_extra_example/tutorial003_py310.py
docs_src/schema_extra_example/tutorial004.py
docs_src/schema_extra_example/tutorial004_an.py
docs_src/schema_extra_example/tutorial004_an_py310.py
docs_src/schema_extra_example/tutorial004_an_py39.py
docs_src/schema_extra_example/tutorial004_py310.py
fastapi/applications.py
fastapi/openapi/docs.py
fastapi/openapi/models.py
fastapi/openapi/utils.py
fastapi/param_functions.py
fastapi/params.py
pyproject.toml
tests/test_additional_properties.py
tests/test_additional_response_extra.py
tests/test_additional_responses_bad.py
tests/test_additional_responses_custom_model_in_callback.py
tests/test_additional_responses_custom_validationerror.py
tests/test_additional_responses_default_validationerror.py
tests/test_additional_responses_response_class.py
tests/test_additional_responses_router.py
tests/test_annotated.py
tests/test_application.py
tests/test_custom_route_class.py
tests/test_dependency_duplicates.py
tests/test_deprecated_openapi_prefix.py
tests/test_duplicate_models_openapi.py
tests/test_enforce_once_required_parameter.py
tests/test_extra_routes.py
tests/test_filter_pydantic_sub_model.py
tests/test_generate_unique_id_function.py
tests/test_get_request_body.py
tests/test_include_router_defaults_overrides.py
tests/test_modules_same_name_body/test_main.py
tests/test_multi_body_errors.py
tests/test_multi_query_errors.py
tests/test_openapi_query_parameter_extension.py
tests/test_openapi_route_extensions.py
tests/test_openapi_servers.py
tests/test_param_in_path_and_dependency.py
tests/test_param_include_in_schema.py
tests/test_put_no_body.py
tests/test_repeated_dependency_schema.py
tests/test_repeated_parameter_alias.py
tests/test_reponse_set_reponse_code_empty.py
tests/test_request_body_parameters_media_type.py
tests/test_response_by_alias.py
tests/test_response_class_no_mediatype.py
tests/test_response_code_no_body.py
tests/test_response_model_as_return_annotation.py
tests/test_response_model_sub_types.py
tests/test_schema_extra_examples.py
tests/test_security_api_key_cookie.py
tests/test_security_api_key_cookie_description.py
tests/test_security_api_key_cookie_optional.py
tests/test_security_api_key_header.py
tests/test_security_api_key_header_description.py
tests/test_security_api_key_header_optional.py
tests/test_security_api_key_query.py
tests/test_security_api_key_query_description.py
tests/test_security_api_key_query_optional.py
tests/test_security_http_base.py
tests/test_security_http_base_description.py
tests/test_security_http_base_optional.py
tests/test_security_http_basic_optional.py
tests/test_security_http_basic_realm.py
tests/test_security_http_basic_realm_description.py
tests/test_security_http_bearer.py
tests/test_security_http_bearer_description.py
tests/test_security_http_bearer_optional.py
tests/test_security_http_digest.py
tests/test_security_http_digest_description.py
tests/test_security_http_digest_optional.py
tests/test_security_oauth2.py
tests/test_security_oauth2_authorization_code_bearer.py
tests/test_security_oauth2_authorization_code_bearer_description.py
tests/test_security_oauth2_optional.py
tests/test_security_oauth2_optional_description.py
tests/test_security_oauth2_password_bearer_optional.py
tests/test_security_oauth2_password_bearer_optional_description.py
tests/test_security_openid_connect.py
tests/test_security_openid_connect_description.py
tests/test_security_openid_connect_optional.py
tests/test_starlette_exception.py
tests/test_sub_callbacks.py
tests/test_tuples.py
tests/test_tutorial/test_additional_responses/test_tutorial001.py
tests/test_tutorial/test_additional_responses/test_tutorial002.py
tests/test_tutorial/test_additional_responses/test_tutorial003.py
tests/test_tutorial/test_additional_responses/test_tutorial004.py
tests/test_tutorial/test_async_sql_databases/test_tutorial001.py
tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py
tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py
tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py
tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py
tests/test_tutorial/test_bigger_applications/test_main.py
tests/test_tutorial/test_bigger_applications/test_main_an.py
tests/test_tutorial/test_bigger_applications/test_main_an_py39.py
tests/test_tutorial/test_body/test_tutorial001.py
tests/test_tutorial/test_body/test_tutorial001_py310.py
tests/test_tutorial/test_body_fields/test_tutorial001.py
tests/test_tutorial/test_body_fields/test_tutorial001_an.py
tests/test_tutorial/test_body_fields/test_tutorial001_an_py310.py
tests/test_tutorial/test_body_fields/test_tutorial001_an_py39.py
tests/test_tutorial/test_body_fields/test_tutorial001_py310.py
tests/test_tutorial/test_body_multiple_params/test_tutorial001.py
tests/test_tutorial/test_body_multiple_params/test_tutorial001_an.py
tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py310.py
tests/test_tutorial/test_body_multiple_params/test_tutorial001_an_py39.py
tests/test_tutorial/test_body_multiple_params/test_tutorial001_py310.py
tests/test_tutorial/test_body_multiple_params/test_tutorial003.py
tests/test_tutorial/test_body_multiple_params/test_tutorial003_an.py
tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py310.py
tests/test_tutorial/test_body_multiple_params/test_tutorial003_an_py39.py
tests/test_tutorial/test_body_multiple_params/test_tutorial003_py310.py
tests/test_tutorial/test_body_nested_models/test_tutorial009.py
tests/test_tutorial/test_body_nested_models/test_tutorial009_py39.py
tests/test_tutorial/test_body_updates/test_tutorial001.py
tests/test_tutorial/test_body_updates/test_tutorial001_py310.py
tests/test_tutorial/test_body_updates/test_tutorial001_py39.py
tests/test_tutorial/test_conditional_openapi/test_tutorial001.py
tests/test_tutorial/test_cookie_params/test_tutorial001.py
tests/test_tutorial/test_cookie_params/test_tutorial001_an.py
tests/test_tutorial/test_cookie_params/test_tutorial001_an_py310.py
tests/test_tutorial/test_cookie_params/test_tutorial001_an_py39.py
tests/test_tutorial/test_cookie_params/test_tutorial001_py310.py
tests/test_tutorial/test_custom_response/test_tutorial001.py
tests/test_tutorial/test_custom_response/test_tutorial001b.py
tests/test_tutorial/test_custom_response/test_tutorial004.py
tests/test_tutorial/test_custom_response/test_tutorial005.py
tests/test_tutorial/test_custom_response/test_tutorial006.py
tests/test_tutorial/test_custom_response/test_tutorial006b.py
tests/test_tutorial/test_custom_response/test_tutorial006c.py
tests/test_tutorial/test_dataclasses/test_tutorial001.py
tests/test_tutorial/test_dataclasses/test_tutorial002.py
tests/test_tutorial/test_dataclasses/test_tutorial003.py
tests/test_tutorial/test_dependencies/test_tutorial001.py
tests/test_tutorial/test_dependencies/test_tutorial001_an.py
tests/test_tutorial/test_dependencies/test_tutorial001_an_py310.py
tests/test_tutorial/test_dependencies/test_tutorial001_an_py39.py
tests/test_tutorial/test_dependencies/test_tutorial001_py310.py
tests/test_tutorial/test_dependencies/test_tutorial004.py
tests/test_tutorial/test_dependencies/test_tutorial004_an.py
tests/test_tutorial/test_dependencies/test_tutorial004_an_py310.py
tests/test_tutorial/test_dependencies/test_tutorial004_an_py39.py
tests/test_tutorial/test_dependencies/test_tutorial004_py310.py
tests/test_tutorial/test_dependencies/test_tutorial006.py
tests/test_tutorial/test_dependencies/test_tutorial006_an.py
tests/test_tutorial/test_dependencies/test_tutorial006_an_py39.py
tests/test_tutorial/test_dependencies/test_tutorial012.py
tests/test_tutorial/test_dependencies/test_tutorial012_an.py
tests/test_tutorial/test_dependencies/test_tutorial012_an_py39.py
tests/test_tutorial/test_events/test_tutorial001.py
tests/test_tutorial/test_events/test_tutorial002.py
tests/test_tutorial/test_events/test_tutorial003.py
tests/test_tutorial/test_extending_openapi/test_tutorial001.py
tests/test_tutorial/test_extra_data_types/test_tutorial001.py
tests/test_tutorial/test_extra_data_types/test_tutorial001_an.py
tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py310.py
tests/test_tutorial/test_extra_data_types/test_tutorial001_an_py39.py
tests/test_tutorial/test_extra_data_types/test_tutorial001_py310.py
tests/test_tutorial/test_extra_models/test_tutorial003.py
tests/test_tutorial/test_extra_models/test_tutorial003_py310.py
tests/test_tutorial/test_extra_models/test_tutorial004.py
tests/test_tutorial/test_extra_models/test_tutorial004_py39.py
tests/test_tutorial/test_extra_models/test_tutorial005.py
tests/test_tutorial/test_extra_models/test_tutorial005_py39.py
tests/test_tutorial/test_first_steps/test_tutorial001.py
tests/test_tutorial/test_generate_clients/test_tutorial003.py
tests/test_tutorial/test_handling_errors/test_tutorial001.py
tests/test_tutorial/test_handling_errors/test_tutorial002.py
tests/test_tutorial/test_handling_errors/test_tutorial003.py
tests/test_tutorial/test_handling_errors/test_tutorial004.py
tests/test_tutorial/test_handling_errors/test_tutorial005.py
tests/test_tutorial/test_handling_errors/test_tutorial006.py
tests/test_tutorial/test_header_params/test_tutorial001.py
tests/test_tutorial/test_header_params/test_tutorial001_an.py
tests/test_tutorial/test_header_params/test_tutorial001_an_py310.py
tests/test_tutorial/test_header_params/test_tutorial001_py310.py
tests/test_tutorial/test_header_params/test_tutorial002.py
tests/test_tutorial/test_header_params/test_tutorial002_an.py
tests/test_tutorial/test_header_params/test_tutorial002_an_py310.py
tests/test_tutorial/test_header_params/test_tutorial002_an_py39.py
tests/test_tutorial/test_header_params/test_tutorial002_py310.py
tests/test_tutorial/test_header_params/test_tutorial003.py
tests/test_tutorial/test_header_params/test_tutorial003_an.py
tests/test_tutorial/test_header_params/test_tutorial003_an_py310.py
tests/test_tutorial/test_header_params/test_tutorial003_an_py39.py
tests/test_tutorial/test_header_params/test_tutorial003_py310.py
tests/test_tutorial/test_metadata/test_tutorial001.py
tests/test_tutorial/test_metadata/test_tutorial001_1.py [new file with mode: 0644]
tests/test_tutorial/test_metadata/test_tutorial004.py
tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py
tests/test_tutorial/test_openapi_webhooks/__init__.py [new file with mode: 0644]
tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py [new file with mode: 0644]
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py
tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py
tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py
tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py310.py
tests/test_tutorial/test_path_operation_configurations/test_tutorial005_py39.py
tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py
tests/test_tutorial/test_path_params/test_tutorial004.py
tests/test_tutorial/test_path_params/test_tutorial005.py
tests/test_tutorial/test_query_params/test_tutorial005.py
tests/test_tutorial/test_query_params/test_tutorial006.py
tests/test_tutorial/test_query_params/test_tutorial006_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial010_an_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial010_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011_an_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial011_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial012_an_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial012_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial013_an_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py310.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial014_an_py39.py
tests/test_tutorial/test_query_params_str_validations/test_tutorial014_py310.py
tests/test_tutorial/test_request_files/test_tutorial001.py
tests/test_tutorial/test_request_files/test_tutorial001_02.py
tests/test_tutorial/test_request_files/test_tutorial001_02_an.py
tests/test_tutorial/test_request_files/test_tutorial001_02_an_py310.py
tests/test_tutorial/test_request_files/test_tutorial001_02_an_py39.py
tests/test_tutorial/test_request_files/test_tutorial001_02_py310.py
tests/test_tutorial/test_request_files/test_tutorial001_03.py
tests/test_tutorial/test_request_files/test_tutorial001_03_an.py
tests/test_tutorial/test_request_files/test_tutorial001_03_an_py39.py
tests/test_tutorial/test_request_files/test_tutorial001_an.py
tests/test_tutorial/test_request_files/test_tutorial001_an_py39.py
tests/test_tutorial/test_request_files/test_tutorial002.py
tests/test_tutorial/test_request_files/test_tutorial002_an.py
tests/test_tutorial/test_request_files/test_tutorial002_an_py39.py
tests/test_tutorial/test_request_files/test_tutorial002_py39.py
tests/test_tutorial/test_request_files/test_tutorial003.py
tests/test_tutorial/test_request_files/test_tutorial003_an.py
tests/test_tutorial/test_request_files/test_tutorial003_an_py39.py
tests/test_tutorial/test_request_files/test_tutorial003_py39.py
tests/test_tutorial/test_request_forms/test_tutorial001.py
tests/test_tutorial/test_request_forms/test_tutorial001_an.py
tests/test_tutorial/test_request_forms/test_tutorial001_an_py39.py
tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py
tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an.py
tests/test_tutorial/test_request_forms_and_files/test_tutorial001_an_py39.py
tests/test_tutorial/test_response_model/test_tutorial003.py
tests/test_tutorial/test_response_model/test_tutorial003_01.py
tests/test_tutorial/test_response_model/test_tutorial003_01_py310.py
tests/test_tutorial/test_response_model/test_tutorial003_02.py
tests/test_tutorial/test_response_model/test_tutorial003_03.py
tests/test_tutorial/test_response_model/test_tutorial003_05.py
tests/test_tutorial/test_response_model/test_tutorial003_05_py310.py
tests/test_tutorial/test_response_model/test_tutorial003_py310.py
tests/test_tutorial/test_response_model/test_tutorial004.py
tests/test_tutorial/test_response_model/test_tutorial004_py310.py
tests/test_tutorial/test_response_model/test_tutorial004_py39.py
tests/test_tutorial/test_response_model/test_tutorial005.py
tests/test_tutorial/test_response_model/test_tutorial005_py310.py
tests/test_tutorial/test_response_model/test_tutorial006.py
tests/test_tutorial/test_response_model/test_tutorial006_py310.py
tests/test_tutorial/test_schema_extra_example/test_tutorial004.py
tests/test_tutorial/test_schema_extra_example/test_tutorial004_an.py
tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py310.py
tests/test_tutorial/test_schema_extra_example/test_tutorial004_an_py39.py
tests/test_tutorial/test_schema_extra_example/test_tutorial004_py310.py
tests/test_tutorial/test_security/test_tutorial001.py
tests/test_tutorial/test_security/test_tutorial001_an.py
tests/test_tutorial/test_security/test_tutorial001_an_py39.py
tests/test_tutorial/test_security/test_tutorial003.py
tests/test_tutorial/test_security/test_tutorial003_an.py
tests/test_tutorial/test_security/test_tutorial003_an_py310.py
tests/test_tutorial/test_security/test_tutorial003_an_py39.py
tests/test_tutorial/test_security/test_tutorial003_py310.py
tests/test_tutorial/test_security/test_tutorial005.py
tests/test_tutorial/test_security/test_tutorial005_an.py
tests/test_tutorial/test_security/test_tutorial005_an_py310.py
tests/test_tutorial/test_security/test_tutorial005_an_py39.py
tests/test_tutorial/test_security/test_tutorial005_py310.py
tests/test_tutorial/test_security/test_tutorial005_py39.py
tests/test_tutorial/test_security/test_tutorial006.py
tests/test_tutorial/test_security/test_tutorial006_an.py
tests/test_tutorial/test_security/test_tutorial006_an_py39.py
tests/test_tutorial/test_sql_databases/test_sql_databases.py
tests/test_tutorial/test_sql_databases/test_sql_databases_middleware.py
tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py310.py
tests/test_tutorial/test_sql_databases/test_sql_databases_middleware_py39.py
tests/test_tutorial/test_sql_databases/test_sql_databases_py310.py
tests/test_tutorial/test_sql_databases/test_sql_databases_py39.py
tests/test_tutorial/test_sql_databases_peewee/test_sql_databases_peewee.py
tests/test_tutorial/test_sub_applications/test_tutorial001.py
tests/test_tutorial/test_testing/test_main.py
tests/test_tutorial/test_testing/test_tutorial001.py
tests/test_union_body.py
tests/test_union_inherited_body.py
tests/test_webhooks_security.py [new file with mode: 0644]

index dca5f6a985cc1b312d7212a76e760ed784e055c0..624036ce974c530b9bb4d818a57cfee5b2c8df02 100644 (file)
@@ -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:
 
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
-* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, 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`.
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responsesObject" class="external-link" target="_blank">OpenAPI Responses Object</a>, it includes the `Response Object`.
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#responseObject" class="external-link" target="_blank">OpenAPI Response Object</a>, 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`.
index 03198851a394d7114a8673fae4b46ee3691d767c..e7af77f3da1af3aa3fed4eded648cd324ef78d57 100644 (file)
@@ -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": [
         {
index 36619696b59dfadeb950cdec6e9da510d006b9d8..c47f939af6b6be04bcffce51ee112743450121ed 100644 (file)
@@ -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!}
 ```
 
index 71924ce8b20486e8b1928ce113d11e184542e177..37339eae575cf9f7fb4baca0e01e8b3e22fe5490 100644 (file)
@@ -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 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (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 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> (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 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> that can contain parts of the original request sent to *your API*.
+The callback *path* can have an <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md#key-expression" class="external-link" target="_blank">OpenAPI 3 expression</a> 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 (file)
index 0000000..63cbdc6
--- /dev/null
@@ -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 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
+
+You will see your docs have the normal *path operations* and now also some **webhooks**:
+
+<img src="/img/tutorial/openapi-webhooks/image01.png">
index a1c902ef2ccbbea64267af2d93d7c887abe3fc20..6d9a5fe708c27831706e772cc5fc6b2c5a4854c8 100644 (file)
@@ -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"
index b7708a3fd98ad2170d880781896623ec8ed80204..4146a8607b5b4278b9d826c5d9e45ee9ff183ce3 100644 (file)
Binary files a/docs/en/docs/img/tutorial/metadata/image01.png and b/docs/en/docs/img/tutorial/metadata/image01.png differ
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 (file)
index 0000000..25ced48
Binary files /dev/null and b/docs/en/docs/img/tutorial/openapi-webhooks/image01.png differ
index 6ca5f39eb1640c99cf94486ceae1ce41c4128c15..cfa159329405c35f681255b925ee1a6bd08fba38 100644 (file)
@@ -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"
index cf13e7470fc887fb6b198fbbce9a835f14397d72..e75b4a0b950fe44695338c1294904e48ff0ae51e 100644 (file)
@@ -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. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small> |
 | `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. <details><summary><code>contact</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td>The identifying name of the contact person/organization.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>The URL pointing to the contact information. MUST be in the format of a URL.</td></tr><tr><td><code>email</code></td><td><code>str</code></td><td>The email address of the contact person/organization. MUST be in the format of an email address.</td></tr></tbody></table></details> |
-| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
+| `license_info` | `dict` | The license information for the exposed API. It can contain several fields. <details><summary><code>license_info</code> fields</summary><table><thead><tr><th>Parameter</th><th>Type</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td><code>str</code></td><td><strong>REQUIRED</strong> (if a <code>license_info</code> is set). The license name used for the API.</td></tr><tr><td><code>identifier</code></td><td><code>str</code></td><td>An <a href="https://spdx.dev/spdx-specification-21-web-version/#h.jxpfx0ykyb60" class="external-link" target="_blank">SPDX</a> license expression for the API. The <code>identifier</code> field is mutually exclusive of the <code>url</code> field. <small>Available since OpenAPI 3.1.0, FastAPI 0.99.0.</small></td></tr><tr><td><code>url</code></td><td><code>str</code></td><td>A URL to the license used for the API. MUST be in the format of a URL.</td></tr></tbody></table></details> |
 
 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:
 
 <img src="/img/tutorial/metadata/image01.png">
 
+## 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`.
index a0d70692e556bd85619eda95f2d980ca258c582f..6594a7a8b5f95c6dd145a8059bcfc04808ab2e8b 100644 (file)
@@ -83,7 +83,7 @@ And when you open your browser at <a href="http://127.0.0.1:8000/docs" class="ex
 
 ## Standards-based benefits, alternative documentation
 
-And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
+And because the generated schema is from the <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md" class="external-link" target="_blank">OpenAPI</a> standard, there are many compatible tools.
 
 Because of this, **FastAPI** itself provides an alternative API documentation (using ReDoc), which you can access at <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>:
 
index e0f7ed25696db898d0fb0970a8a9119a09350176..6cf8bf1813788e5f00c6074ae291c8adb28c800f 100644 (file)
@@ -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 <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
+You can declare `examples` for a Pydantic model using `Config` and `schema_extra`, as described in <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
 
 === "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:
+
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#parameter-object" class="external-link" target="_blank">`Parameter Object` (in the specification)</a> that was used by FastAPI's:
+    * `Path()`
+    * `Query()`
+    * `Header()`
+    * `Cookie()`
+* <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#media-type-object" class="external-link" target="_blank">`Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification)</a> 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 <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a>, 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 <a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md#fixed-fields-20" class="external-link" target="_blank">`example`</a> 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 <a href="https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.9.5" class="external-link" target="_blank">`examples`</a> 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 <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object" class="external-link" target="_blank">OpenAPI definition, to the `Parameter Object` (in the specification)</a>.
+### Summary
 
-And for `Body()`, `File()`, and `Form()`, the `example` or `examples` are equivalently added to the <a href="https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#mediaTypeObject" class="external-link" target="_blank">OpenAPI definition, to the `Request Body Object`, in the field `content`, on the `Media Type Object` (in the specification)</a>.
+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. 😎
index 64dc4037278fb2d550b1a0b202abd8ca02a41aa5..030bbe5d3eba1ccb5016c300b5dcaf367e2fb257 100644 (file)
@@ -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
index 561e95898f5f46521516a77a1f60fcf0f87a7515..35e31c0e0c943fc4e0fdc0573089e7bc10f99370 100644 (file)
@@ -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"] = {
index 3fba9e7d1b272291157cc091229f954373cc1109..76656e81b4246ff70ea34d46ee2abd395d9f5919 100644 (file)
@@ -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 (file)
index 0000000..a8f5b94
--- /dev/null
@@ -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 (file)
index 0000000..5016f5b
--- /dev/null
@@ -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"]
index a5ae281274df2137e58a4cf93ade4fc2e689d4bd..6ab96ff859d0d9c3cd47ac01b9fed22a788e4f32 100644 (file)
@@ -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,
+                }
+            ]
         }
 
 
index 77ceedd60d39ffe45d938576b25c3cb7ece59291..ec83f1112f20fb80798d67ff575e2e60f899bf7c 100644 (file)
@@ -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,
+                }
+            ]
         }
 
 
index 6de434f81d1fd057dc304ae728ab5baf73e594d9..70f06567c378774ed6a22ad16b49fb0bde158739 100644 (file)
@@ -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}")
index e84928bb11980c989aafe14394870e6ffa811beb..27d78686763e5ca6b8caf779da4582e715de13d7 100644 (file)
@@ -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}")
index ce1736bbaf191935c99f91f08eae7f53b9fabd7a..385f3de8a1c81d6564632a4e1b78c356ac03f932 100644 (file)
@@ -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}
index 1dec555a944e560730aacf39a3707026d38fe3cd..23675aba14f8fc68e6f114bdf6197e434cba5e32 100644 (file)
@@ -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,
+                }
+            ],
         ),
     ],
 ):
index 9edaddfb8ea75396b61b7444da261f3b8c4fc52a..bbd2e171ec9ddf475b1ac7a35d4611ceabea5d9b 100644 (file)
@@ -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,
+                }
+            ],
         ),
     ],
 ):
index fe08847d9898ee3d1697fc616abdd79f395e900c..4728085617f6e37f251c725978ea07fc25d73f42 100644 (file)
@@ -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,
+                }
+            ],
         ),
     ],
 ):
index 1e137101d9e465aef37b532f78d45dfadf95e2ea..2d31619be20006347881f9f343c95017f004bb69 100644 (file)
@@ -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}
index b67edf30cd7158f5b59dadd4f429376aa1208e36..eb49293fd8e240acdc3566194c8733f8787e72af 100644 (file)
@@ -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}
index 82c9a92ac135336b42f4011737c1b60a4760b2e9..567ec4702430e76d251d19cc8927d9cf3deb8707 100644 (file)
@@ -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",
                     },
                 },
-            },
+            ],
         ),
     ],
 ):
index 01f1a486cb77584e7221adcf7fe6b8b50e8d5093..026654835633ff6bdeeaba8710bc328bc1dd2ca9 100644 (file)
@@ -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",
                     },
                 },
-            },
+            ],
         ),
     ],
 ):
index d50e8aa5f8785f4f549df022b64b83ef21aa5e67..06219ede8df8de5712bbd15b217bc51726cfcd24 100644 (file)
@@ -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",
                     },
                 },
-            },
+            ],
         ),
     ],
 ):
index 100a30860b01a18c96b0fa0cd072b7feff8408f5..ef2b9d8cb9276befff4e2da1f58a5d79414d1783 100644 (file)
@@ -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}
index 9b161c5ec832fa582acf30945bf4f78d16a9b342..88f861c1ef0702cd8c0608cb565113a3261050d2 100644 (file)
@@ -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,
             )
index bf335118fc791c42fc38e6ab2fb81fb4a8a2b580..81f67dcc5bf59d32c7c8e59d5f345002d114a9ef 100644 (file)
@@ -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,
index 81a24f389b63be0eee554c679479e8a4f83fc5bc..7420d3b55a0979a31ee07a8b67c4cf68bbfab04c 100644 (file)
@@ -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
index 6d736647b5b03f3305e5e5e8f36d13e9e951d9ec..609fe4389f2bb18c35dfa8c32a9c4aa985f37acd 100644 (file)
@@ -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
index 75f054e9dcbf5d3ac91db477b4fe31a05599aad1..2f5818c85c3803baeb76fd9bec1eb74d8b42f47c 100644 (file)
@@ -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(
index 16c5c309a785f9e6d2a6f9cbd82cadd5971fa819..4069f2cda67e2a1d1c9dacb4895aac803f83966c 100644 (file)
@@ -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__(
index 5c0d3c48ecfd98e0d957d7bf2f0bc319ec05b16b..61dbf76298a88936789691d6d01d045faa65c19b 100644 (file)
@@ -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"]
 
index 516a569e4250dc81e15138b1fa7efc51d838b45d..be14d10edc66e00d6b050803046400e79ceeafc6 100644 (file)
@@ -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": {
index d62638c8fa3cd7bb49cb93da5673ff751d3261f8..55be19bad25a85d57f7ded06b6c04c30ac9cd2c0 100644 (file)
@@ -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/": {
index d2eb4d7a1942a2a5cfc1acaf9c38cf655c78d0bd..36df07f4683f614c0f737408931c7bc4a0f384fe 100644 (file)
@@ -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": {
index 5c08eaa6d2662afb43ed7c833f7a0e59f1f84988..397159142783d576e0b31e5ec7ef3242613a497f 100644 (file)
@@ -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": {
             "/": {
index 05260276856ccb8217eb450da3a25cb2f0a6440a..9fec5c96d4e17277ac0e9c8215bd499a00775411 100644 (file)
@@ -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}": {
index 58de46ff60157727f7564bfbb27b8f6c5a4342ce..153f04f579880b50a4cf46ffc59c574c875aa4fe 100644 (file)
@@ -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}": {
index 6746760f0e295a4468b92acfa1b249fd49e48dbb..68753561c9ecc983e74f9d0ac77b34bae31e0c4a 100644 (file)
@@ -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": {
index 58d54b733e763661478168fd819a52907d01a82e..71cabc7c3d1142d15bf3524669cddf48e530504e 100644 (file)
@@ -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": {
index a4f42b038f476fb8a350363271abbb8ec6d18456..5a70c45418cfc8b18b9ad87a41f69ed2278241b0 100644 (file)
@@ -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": {
index e5f2f43878b6fd3dda1fa7bbebaed0c945b34410..b036e67afe690ff4919d01b5952c177b021202ac 100644 (file)
@@ -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": {
index d1b18ef1d2f558e840f86a0585b4ff703c98ee9e..55374584b095a23cc1beb90f7193c44834c6ccdf 100644 (file)
@@ -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/": {
index 285fdf1ab717effe45ff500a6ea86dd7775ff1d8..4f4f3166ca4c765c0bec0c049cbab21bf9a40c53 100644 (file)
@@ -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": {
index 688b9837f2d05ac57d95ee85bd4429e58a1dd795..ec7366d2af7025bc89c028b3728333b39e503482 100644 (file)
@@ -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": {
index 116b2006a04a2fb03414792b9ef640c4f64fdafa..83e86d231a6f9b9448df70c7d7b095974f7cbae5 100644 (file)
@@ -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": {
             "/": {
index bf05aa5852ac99fac49574bb2b87b0e25102ba4a..b64f8341b8c1f3f72d1b528139dd06f02064dc00 100644 (file)
@@ -57,7 +57,7 @@ expected_schema = {
         }
     },
     "info": {"title": "FastAPI", "version": "0.1.0"},
-    "openapi": "3.0.2",
+    "openapi": "3.1.0",
     "paths": {
         "/foo": {
             "get": {
index c0db62c19d40c425898d4c5b5a0fe1bfb3226bec..fa95d061c4dff6d1db793afc2b3d1e7322678c5c 100644 (file)
@@ -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}": {
index 15b15f862449886acc2963f9025e2106f3017a81..6ee928d07f8717db04e0926456493ff74080e72f 100644 (file)
@@ -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}": {
index 0b519f8596f5bf7ee53103adc8d550ce1fb62540..c5ef5182b73f786ad8d3e57a1927081b54b5a91e 100644 (file)
@@ -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": {
             "/": {
index 541147fa8f123b1d619630172a4fc820e3429b6d..cc567b88f6f68af88bcb3c69ca62db3c4b3b70f9 100644 (file)
@@ -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": {
index ced56c84d30fd342a8f79cfda718cbeda31ba65f..33baa25e6a7980130d24ff583610c7cdf49d34a0 100644 (file)
@@ -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": {
index 1ebcaee8cf264377098d53adb2a59089daa0e623..cc165bdcaa2589178ca590d2f76fffc8627df359 100644 (file)
@@ -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": {
index 358684bc5cef8194cb048540c5a52ac8c93fb862..96043aa35f44d10ca3469f888404250b9e2638b6 100644 (file)
@@ -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/": {
index e7a833f2baf03f75d85bf2fca478c43e498e826d..c1f0678d0130b7c9b589c010b664fc1136f299b0 100644 (file)
@@ -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/": {
index 8a9086ebe1dab2ae9f8a27805f4736c8e6baa9d4..6f62e67265101dbbf06eb349d2e75ff7577b11f1 100644 (file)
@@ -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": {
             "/": {
index 943dc43f2debda354c8e8336bcb9ba03022eacba..3a3099436799cb90110a0589a3f08deb978ba465 100644 (file)
@@ -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": {
             "/": {
index 26abeaa12d68cb601b1491381183ef6c4410c17f..11cd795ac584657e04008e71dab7811d5c7e18a8 100644 (file)
@@ -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"},
index 0aef7ac7bca04493dbc669cd728d11b9aca501b4..08eb0f40f3d1f090fd73390a7966ccfda31c5ee9 100644 (file)
@@ -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}": {
index d0c29f7b2d2dfdedc70bd7f599620c86475ca997..26201e9e2d496f32c5a0f886a24e1d701c81b70a 100644 (file)
@@ -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": {
index a02d1152c82a62d788824bffe3f3e7b810a56cfc..8f4c82532c2d252a9fb71b22c44aee5780b3ffb3 100644 (file)
@@ -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}": {
index ca0305184aaff190b08e67fa932cf67990a56a2c..d7d0dfa052910ae3af6af9f7d652844a80ef447a 100644 (file)
@@ -50,7 +50,7 @@ schema = {
         }
     },
     "info": {"title": "FastAPI", "version": "0.1.0"},
-    "openapi": "3.0.2",
+    "openapi": "3.1.0",
     "paths": {
         "/": {
             "get": {
index c656a161df4dfd6e7beb7f0b4e27973d2ae45778..fd72eaab299ed9c6080c5fbe6905d9f3e15ffdf0 100644 (file)
@@ -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": {
index 14770fed0a80aa174e6abec7f0218b4de20bfef2..bf3aa758c328959545b2386eff9be46a086db416 100644 (file)
@@ -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}": {
index 32f6c6a7252db55961a20542621ec9b969a57eaf..8424bf551ed7639fb40cb502d5c5b42e9a2347cd 100644 (file)
@@ -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": {
index 1861a40fab0c52b08d26ce53ba2aef95ee2c5e51..c3ff5b1d25a8511482e5c9b7ba6e8170c0a68064 100644 (file)
@@ -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": {
index 2d75c7535827d7ca3b6aaa49804cbb7f8c2d7962..706929ac3673c320fcc9d8a4e15b4ca9f167640e 100644 (file)
@@ -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": {
index 3851a325de585b1ba6bea3a4f1b4bdfaeaebdb78..3ca8708f1263a7c47c9cb78c0e0c933b3f70aa60 100644 (file)
@@ -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": {
index 7decdff7d0713ca99114845000579f34b5f598a8..7a0cf47ec4004c14694d2202b3f97eb032fb355a 100644 (file)
@@ -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": {
index e462006ff173566951f1234009c0f93d0ee47597..660bcee1bb7eb53457b6021b959fda109d6e79e7 100644 (file)
@@ -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": {
index 41021a98391cdbc0bbf7572a6d6e373953f68f44..45caa16150ed7da89ccd91801334469f5af122dd 100644 (file)
 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",
                         }
index b1c648c55e184925fec3a0cda0773c98bd47706d..4ddb8e2eeb11bab335f0b9cb2e386d504f9fab77 100644 (file)
@@ -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": {
index ac8b4abf8791b862393e54119fd4d639877d0840..d99d616e0679656aa3dfc0ce4cb22b86d2a3e9ee 100644 (file)
@@ -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": {
index b8c440c9d703f2faa8224f7d46d2cc26d096b3b5..cb5590168d30cc755912ad8315483c54899abc53 100644 (file)
@@ -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": {
index 96ad80b54a5bfff5f845a3e3dd6bd6ba2962ee77..1ff883703d59d1f75f70ad4f1e0b915f9e29e1fd 100644 (file)
@@ -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": {
index 382f53dd7819785905f293e79b15d9238457f5f5..27f9d0f29e6d6d21c42623b0e330453e96181fee 100644 (file)
@@ -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": {
index adfb20ba08d0c9efd2b5b1af6ccb30b95590d71a..6f9682a64fef3d5e068545eff4080c65a2b3200a 100644 (file)
@@ -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": {
index da98eafd6cce22daa1314522e0cbb16db5d34b61..dc7a0a621aabe2217fcb870d0474b660861696b9 100644 (file)
@@ -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": {
index 3c08afc5f4d8b602b5efaf56806cdd8a4d7329f9..35dc7743a23eaee9edc66ee007c4e552cb580b58 100644 (file)
@@ -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": {
index 99a26cfd0bec3938aab24433a6026dd94596ea06..4cc134bd49ab98dc661f08db527f8afdca5da4f7 100644 (file)
@@ -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": {
index d3a7542034685be08a99a86058c1afa240dac6f9..51928bafd5988bbb69ece958a6d99250b7d5b12f 100644 (file)
@@ -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": {
index 3d7d150166bf7befb1cc8f6528446d0957cd7481..bc79f32424b6a9081eb5eb6d8d1b4b0f567a0e0e 100644 (file)
@@ -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": {
index 180c9110e9919d20eb2d41e29df0587f5b6a04f2..dd4d76843ab2922b8c6acb8f43b2415b832a1921 100644 (file)
@@ -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": {
index 7e7fcac32a8e72f1e617a53b6c4f7a6f854f9679..9b6cb6c4554365a40cd78cadf05ac963fa0d3ccf 100644 (file)
@@ -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": {
index 470afd662a4e607c807f9539e0b43a324a35287f..9fc33971aec6c4ce4dcc656f61648fb98fd3614c 100644 (file)
@@ -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": {
index 44289007b55d49d6084265b24ba3d4bfd0382068..02122442eb113940b1297368eec7eb8c17669e72 100644 (file)
@@ -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": {
index f24869fc323600f0c800be0f8f58410a4ef7aade..5b9e2d6919b0989b44eb0d4a9fb3443985bb7917 100644 (file)
@@ -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": {
index 6d5ad0b8e7e00c104d5ea480817f36b326753aa8..2f11c3a148c0dd2f5d845b88e6cc016d23f660c6 100644 (file)
@@ -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": {
index b596ac7300d9d514a396c8f1811305d7145aec9c..943da2ee2e93e18c9280506b9ec208a35060b8aa 100644 (file)
@@ -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": {
index 2a25efe0233254929ac78f9682475d616435b276..133d35763c3edcbbec224f2b26fb8d10fc512415 100644 (file)
@@ -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": {
index 721f7cfde5e545c738b76aa16cd75f932c6a98ee..4e31a0c00848cbed7627f31dded232d26217cc1d 100644 (file)
@@ -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": {
index d4c3597bcbe2e6cfc1bc28c34c4c4b4b957b55bf..1e6eb8bd7f6738359b50bae97bbf4fa91f7274e9 100644 (file)
@@ -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": {
index 23dce7cfa9664ca7f4f92a23ae1a1bca197709dd..73d1b7d94cebf0ec68950578f2d44a1b9ef071b7 100644 (file)
@@ -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": {
index 6df81528db7ecb21e4a193b9e090ae41bdd70b03..f2097b14904a4e76f81a6d0d220f8bba4d6b8d26 100644 (file)
@@ -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/": {
index c119abde4da18d5b81b1a57bca3004f8f1ed63c4..5386fbbd9db6253296acb0587f23d2290c84e420 100644 (file)
@@ -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/": {
index 3ef9f4a8d2448495012d5e8fe18387ce58d7e9be..b24c1b58ff7a504e78b8918f9ff09a33690fec6b 100644 (file)
@@ -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": {
index b6425fde4db197034abbe0159298753101e290a5..cda635151e451b943084c03382f819b21b7592aa 100644 (file)
@@ -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": {
index e5dcbb553d589313e4c3d4e3a97a98324445fd28..4c9362c3eb0a868d80ab6c1d30c226dbf13a8c9c 100644 (file)
@@ -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/": {
index 9ff48e7156dc51b394d7b92497baa05cba1bf468..6e6ea846cd33d1f5c07dc58ef2dc502df743e1c4 100644 (file)
@@ -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/": {
index 206de6574f893ea637f908004d7aea7e2f8fd520..1e322e640ed3685f8d7934f84e8e0bdcbc900e3a 100644 (file)
@@ -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": {
index 5884de79308170c2535aecf9482019df620ff035..44cf57f86281ca6f706f0f886555d84d1e7791fb 100644 (file)
@@ -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": {
index 8ac719118320e673dccf5623da05783cbdd96b4c..e817434b0dac9ae551940841a67b1c3b4efa4dd4 100644 (file)
@@ -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": {
index 96f835b935aaef44f643eff34e42ab49377b2f13..229fe801636d686e90d18ca8ad492bcd82cb5533 100644 (file)
@@ -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": {
index c5a0237e8035506207b671285a463f84ed2cc2ba..dce3ea5e2956d76b80c6890d6cf93535dbcb0a84 100644 (file)
@@ -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/": {
index 4fa1f7a133e5445a3c791986b23c49823c8504ed..c37a25ca69bd706d7c2d98d6acb227d2c04da76c 100644 (file)
@@ -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/": {
index 3d6267023e246aac82c4e08fca6847fa921a2335..3afeaff8406918f6fa656eec4141fcb5b1b4ff14 100644 (file)
@@ -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}": {
index 6182ed5079025221eba51cacb3ac6ece77eddd15..8e084e152d69c14f5c2b8e08629085fe1f9684e6 100644 (file)
@@ -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}": {
index 77568d9d4f2166e7be6ceee576d9bd55ba27dd12..bd34d2938c45532873fdd6d5531f6005ac0e4af3 100644 (file)
@@ -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}": {
index 3fbd91e5c2a3ca6bae7616e11a0232153f751d55..5fc8b81ca00298b618d45ce1da08081bfb8d01d0 100644 (file)
@@ -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}": {
index 3da362a50588ea611dd086ba4b33f77d31da16fc..8126cdcc6cc015c55826061584ab0ba625db02f4 100644 (file)
@@ -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/": {
index 7533a1b689e76737652a23e4ed54140800d4d231..a070f850f75930b10c5606d889cfc00e139c1535 100644 (file)
@@ -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": {
index 930ab3bf5c7d7359330823856c1df019f0cbdd92..ce791e2157b31984b88a99bdcbf0ea29daa8a34e 100644 (file)
@@ -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": {
index ae8f1a495dda6a57cfa9f06b128c100a77c2be99..0ae9f4f9332f631504b499ab0139d29bf4a2d82c 100644 (file)
@@ -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"},
index e67ad1cb1fc0723de9bbac62d683f6e17fb087d4..576a411a4a1d4aec71cc924ef12bbba02eaa9de6 100644 (file)
@@ -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"},
index a13decd75b86dfebd64e437142c600f6be93054f..7da663435a274dbbc8efac88d44565f0ed5fc830 100644 (file)
@@ -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/": {
index 64e19c3f391c0b2f40b36c2aedd9465443f6e064..8f42d9dd1d9035052eecd327d465a10a7f6045e0 100644 (file)
@@ -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/": {
index 70c86b4d7f2001f1abdb043a878d9666dc4fa990..44694e371ed57396efb827a7cfe2ced472024bca 100644 (file)
@@ -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/": {
index cd1209adea5aae6050c3e3c928d1a4511cfb7025..469198e0ff10014a970b8b6ceef927562d380f50 100644 (file)
@@ -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/": {
index 5ebcbbf574aa720f80cf72df8a02508045ae087d..a68b4e0446a9a5456634383ad136bc06c0ee047b 100644 (file)
@@ -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/": {
index a7ea0e9496664717c1c4bbfcd32994ed2262d6ba..4999cbf6b5f3650990960afa4b91ad59b7b67f29 100644 (file)
@@ -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}": {
index 32f996ecbd5d5d4b054abce645e287b910fff98a..011946d075876e3fe003f9c05499f1475dd78969 100644 (file)
@@ -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}": {
index 20e032fcd8a0540cac20b32a9397f063ae655103..e7dcb54e9c86ea3b27aa33d565a93d6e03a47fd9 100644 (file)
@@ -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}": {
index e3baf5f2badf932d1e86d30fee8beb1ee8e8c54f..f1015a03b4695b22c56d24ac0bab4e69892e04c6 100644 (file)
@@ -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}": {
index 4c2f48674a7a3e3acbb0443447c1155896357e85..29c8ef4e9cfaade9e0a4159411f6842c0255ac67 100644 (file)
@@ -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}": {
index 496ab38fb97a60edab50150379d75f3273ed190f..ce41a4283425f90d1c19551cb5e5817bb0e7dbd0 100644 (file)
@@ -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}": {
index 74a8a9b2e4a4fc8200674c9f2d98a83c3494bd8c..acc4cfadc765298fc7f81c16fcec7365f949456f 100644 (file)
@@ -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}": {
index 9c764b6d177fbf353d94136f9eb7595993393eb7..a8dc02a6c2e91d6ab4783c46f601f1a71c0d2b3d 100644 (file)
@@ -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}": {
index 0cca294333b53557f0f7df967a7ca095badc3239..f31fee78e4839a51d8143902e740e02526ac9e23 100644 (file)
@@ -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}": {
index 3b61e717ec399a4d34312c186fb88ca130779af7..0e46df253f716aaede32e593c65e5eca7cec3d3b 100644 (file)
@@ -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}": {
index b34377a28c3577362af46d56360b2349457b58ee..8555cf88c5ad778afc93c02db51518e31b4e7d78 100644 (file)
@@ -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}": {
index 9b8d5e15baa28ce99c67217c79f694c189193a2b..f4d300cc56c9c7f42277540f9bf85a483a4e195c 100644 (file)
@@ -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}": {
index f8af555fcd791e0a122c99175a47195b9b647d33..afe2b2c20b608333699ec49213353c3403ce205a 100644 (file)
@@ -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}": {
index 06e2c3146f69941ba6e464285fdfdc574230fbc2..033d5892e593c7c3da20962b8cea74e0f0a1ea5b 100644 (file)
@@ -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}": {
index 82c5fb1013209b51115863b5a89cf79b4cf51e91..8fcc000138983251e9fedf5153bc6fe84fab2d9e 100644 (file)
@@ -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}": {
index 378c241975258697502eec3565aee54e551e8764..ac39cd93f424845cfc85e2f85c94b44c892a441f 100644 (file)
@@ -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/": {
index 5ca63a92bd46748c4bafc2a1616e8ec39057d4b1..0800abe29b1b50c27f23009ca9997a16849e4902 100644 (file)
@@ -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/": {
index 939bf44e0a7740155618fbfe3ba280d8d977e957..151b4b9176699d2d1aa91e8e0f529afc0bf3fc6c 100644 (file)
@@ -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}": {
index 5f50f2071ae4351e550c94d1ae79b5a6baa476de..c4b4b9df338b71c812a7f4132aec3fbbb7d71c53 100644 (file)
@@ -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}": {
index d4fdabce66c75e3ad4a43ee14fbc63f1f3a17536..940b4b3b8699f72531c7a20ee9b1412f86dfe004 100644 (file)
@@ -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}": {
index c1d8fd8051e6d1b2c09b48468f8d8c30ee6a1e9d..a43394ab16defd5ccf2db29217eae983fde7e75c 100644 (file)
@@ -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": {
             "/": {
index c3511d129efa92bc24110353681dbd36b7e9784b..902bed843bb0372dc212faf4140be5ac239d9c6a 100644 (file)
@@ -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/": {
index f4f94c09dcc594a5a01159e34d92f1cef63263c2..aa5807844f281a31d416e1e2845f777c06795e9c 100644 (file)
@@ -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/": {
index a80f10f810564743b3579306269342d676520bcf..ffb55d4e15c4026f7330fcfdf640f6b3c3930d46 100644 (file)
@@ -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/": {
index 1be898c0922c0f58553d08a2b992aa826c4ca897..9bc38effdee7fa9e4409763d7b60f588ca256427 100644 (file)
@@ -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/": {
index 7ba542c9029908d7dd0d557b06f4f8cc382efc4a..bb2953ef61a4126a16d7d508eff9189dc8ccb311 100644 (file)
@@ -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/": {
index da2ca8d6203910b77383c490ffea0edc1dcfaa35..fc8362467362eb72a0400bcb8fbf9287485ffe40 100644 (file)
@@ -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/": {
index f681f5a9d0bd8f9d1982a3ed593ab83585316445..91e5c501e3fad25746269a2ec7d8855363200e7f 100644 (file)
@@ -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/": {
index ef0ba34469acaf5a5998e5070b4af22a4ed392ab..de60574f5e4ee3587b4b40ec52b7503c0431a183 100644 (file)
@@ -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/": {
index e4b5c154669496425d7b3cf4f6673836cd64c2fe..889bf3e929f4b18723cae60cc160017e6cc71a6c 100644 (file)
@@ -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": {
             "/": {
index 9f1b07bee96c95178db5a9d355aeab0f22df0d55..2d0a2cd3f6517831152839b616484742a43feeb4 100644 (file)
@@ -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": {
index cf204cbc054371ffb1f65bbaae3e67551dd0bf5b..1739fd457076cb85713e4c093b1c860da50a22b8 100644 (file)
@@ -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": {
index f196899acaa28cc0ccd2e68c3905fa35c06db66b..51aa1833dece832e42b399ccc9b8bc95d8101254 100644 (file)
@@ -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": {
index 26ae04c515441098d206a2913e44eed6ae3404c1..e20c0efe95c608844ca0d5950de1df65f2e70b8c 100644 (file)
@@ -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/": {
index 675e826b11ecaa41e1b4ad5deadf28f9291c4bbb..e122239d85044090b4883d047d15342950cc6816 100644 (file)
@@ -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": {
index f3378fe6299786bb2bf198b93ba2513d4a3ad9de..204426e8bca80f24eb01bae87c700913c47b70dd 100644 (file)
@@ -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/": {
index 974b9304fdbf059c9e9ae7b595f6a06401d164e2..a8e564ebe6136de316f1fb6c602f54283ea4180c 100644 (file)
@@ -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/": {
index b1ca27ff8b0f918eb53b3424d4676bc93a401e5b..4e6a329f44bc3e8f568c3bf7cc44e69db79d622d 100644 (file)
@@ -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/": {
index 70bed03f628621f2cba80c552f0da6413c7772af..205aee908a3a1bfecb3ec640b306926e387ad57a 100644 (file)
@@ -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/": {
index 9c5723be88570c8fef8e6ebd23c2a8d73cfcec1b..73593ea55ecab874909c5fea50b7b79f2fdba348 100644 (file)
@@ -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/": {
index 1bcde4e9f47ec0b5743f62a53e00e5a22efb856e..10bf84fb53e17fde718d5e0cc824e05a0ebbcdcc 100644 (file)
@@ -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/": {
index 298bc290d291b7150bdcc7eaf185f485e5404ab6..d16fd9ef707d8b641010ca41c272e0ea9dcef335 100644 (file)
@@ -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/": {
index f985be8df058e6c188e2179d8409e1f990a5f4ea..46fe97fb2c731933d2c79eaa17dc38d42be62c11 100644 (file)
@@ -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/": {
index fc028670285c5fe423160354a3e79a686a6c12be..c6a0fc6656090b07e61a797419c21c9a179c8142 100644 (file)
@@ -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/": {
index 1e37673ed8b0ef2c4b568c4043dfcbe891e69b4d..30431cd293c37588e02a7afda861db681bb910f4 100644 (file)
@@ -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/": {
index ab936ccdc0b303ab7a8ff590179ed1931665bb95..9793c8c331abbf461f2d3332c1a1d613eb297fed 100644 (file)
@@ -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/": {
index 2e9c82d711208c074cd93854049ee3a01ad2518a..6fac9f8eb3938eb7e91fa0be31fa279d75ca3519 100644 (file)
@@ -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/": {
index 919066dcad779f0f8ac5737fb303d73b3df08173..810537e48625323a5991625305bb484662c7cb4a 100644 (file)
@@ -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/": {
index c237184796ca87510d66cba04473ecf463512d9f..f17cbcfc720d0b04a6736308d172c50b2db732d9 100644 (file)
@@ -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/": {
index b92b96c0194e93d4818b14883a34b59f9b5ddd15..af1fcde55e06e6b9099f05b4b5f5ff2ac28a964d 100644 (file)
@@ -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/": {
index 2ddb7bb53285ed12a61386d18e3cfa4e455b8982..c33d51d873a551b30a7b504ffc0a67975827bb3c 100644 (file)
@@ -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/": {
index 595c83a5310ea99c9bceedf094d1fac957d6b0cd..d7bd756b5ff2515ee97d3d835e93c23b9422a706 100644 (file)
@@ -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/": {
index 52f9beed5daa35aadfa64164dc7b7c9225950469..a5bb299ac03263fbce3f5d9786e698fc5b10d58e 100644 (file)
@@ -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}": {
index 882d41aa517be2f8d4366ea8bb1b683f0a6b17a0..81cbf4ab6d90a5d6a5f87c457749a0dcea5da43e 100644 (file)
@@ -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/": {
index b2820b63c68657721f25ecced33813c06f41c584..0ad1a1f8b24bdf4792751fd1fd0ea9e7112ce56a 100644 (file)
@@ -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": {
index 6e71bb2debc7e6fde1f3bd044e85525e8ec9b4be..a85a313501428f2b4fbe71637f94b97cc2d2acf4 100644 (file)
@@ -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"
             },
index 07a83499038525cbf6708d21b71da1776457dedf..39d2005ab781f0e871dd5b8af90a82988b49994c 100644 (file)
@@ -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}": {
index 76836d447d89114f902e0ebd15405488b178a07d..3e497a291b53ead0e2438b2241e35ca1d290a951 100644 (file)
@@ -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}": {
index 158ee01b389a339e003a87adccd66051fdb4ea37..b539cf3d65f79de2636674bd9d27cd501b8bdaab 100644 (file)
@@ -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}": {
index 5be6452ee56caa47e3d447f246e99c6c7063bbba..efd31e63d7ced23ec4e9329b9600ad1b763b739d 100644 (file)
@@ -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}": {
index 5413fe428b72fc957bfdcf11d08d5ad2e0f68c63..733d9f4060b3d4e59b76848a5ce66b3913a34ccb 100644 (file)
@@ -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}": {
index f08bf4c50970872ec898da7d00c1448197440c4e..21192b7db752e964e0a4216593a6a50201f20a97 100644 (file)
@@ -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}": {
index 407c717873a839204c3c597368e35b455c735a24..c17ddbbe1d5507b0344ce8f95f4f0cb8eb043697 100644 (file)
@@ -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}": {
index 47790ba8f94dded5d5d77974368d0c7c7bd778f3..71f6a8c700b35508aa7bc7cec45c72c05f8b8a56 100644 (file)
@@ -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/": {
index a98700172a1b6522a132b236dcb1e6a374bf903c..5475b92e10fee8c52cda394d932bc38bdf3ffda7 100644 (file)
@@ -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/": {
index 7c094b2538365220ae5def48c005f2e62f743d7e..b0861c37f7dff322d6db46504cdaf959209d406f 100644 (file)
@@ -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/": {
index b403864501ee11d60f748613ea7d7a9026d99919..7278e93c36ae40070c1e1c9c204a6b9fe699ffdc 100644 (file)
@@ -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/": {
index ea37aec53a95f3126eb724f612b573c052b95a0f..6cc9fc22826dd5e163ea35417cb6d40866de877a 100644 (file)
@@ -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": {
             "/": {
index 8b22eab9eec38850928a9a7ed0472aa277a70ed1..1cd9678a1c8e4bc1a6e0e7cf00714817e54e7ea8 100644 (file)
@@ -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/": {
index 99a1053caba2844545dc40d51e0685b07aff1487..8809c135bd706cbb18e1438335b1a2807035a261 100644 (file)
@@ -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}": {
index 091c74f4de9a047e5ad6672a7c3cc3e280d8d60a..efd86ebdecd462b70f7eac7b763bb654c55a4646 100644 (file)
@@ -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}": {
index 1639cb1d8b67b95a3f54c3d4a48e1922b87ec753..4763f68f3fabb0cc1a4da3279b3566f99093808b 100644 (file)
@@ -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}": {
index 246f3b94c18f315a760a07b15f1cbff7b63b0a62..0c0988c6431af6c87ef7e9e3b0a161e4a0cafb12 100644 (file)
@@ -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}": {
index af47fd1a4f52c9c58ea5ba96d6f975a64eae32c6..f356178ac7c0dc50f554ddbe39d31c06346da357 100644 (file)
@@ -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/": {
index 4a39bd102268a956aec934842f432cd128f5918b..4dd1adf43ee9e51256d95defd6b3b630eeb17c6a 100644 (file)
@@ -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}": {
index 80f502d6a8cc2f82e998eed69c7c36290911490a..030159dcf02ea7a06922dbd7b655bf69aa44f7ba 100644 (file)
@@ -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/": {
index f0ad7b81600818ec00861d9ca73442f8a1dda186..3755ab758ca1863c4b5390710ac9de99c8a5a09f 100644 (file)
@@ -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/": {
index d095c71233037fdfd3f07cb17631aad55cc860c5..207b3b02b0954f7608d9e468d2b188f862507ac9 100644 (file)
@@ -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/": {
index bf176bba27694bc67c757329992254e871d10ba7..bf51982b7eeb4d1351084bf98338edb8939a123e 100644 (file)
@@ -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/": {
index 516abda8bf45f001a6f28fb511d4580c3a1bf707..545fc836bccc19813bb1e277d5c119bc13881cfa 100644 (file)
@@ -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/": {
index 97493e60402cc2ab205b446fc978efc437efe934..cfd581e33f98f29fe52d70db636997758205e588 100644 (file)
@@ -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/": {
index e0c60342a79be80230f35d9abf0bca8937e4b90e..c8d61e42ec34f20030aeab5c43fa5f2dbb79ab17 100644 (file)
@@ -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/": {
index c1bc5faf8a7d96acdac861ad0d0410b7a053870a..85150d4a9e8e217e3682e237174e326cca454e07 100644 (file)
@@ -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/": {
index 81871b8c6d85756ded978f05dedcfca9f79d9f79..f189d85b5602b39d3295ec5493824cc1f85e5eff 100644 (file)
@@ -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/": {
index 99dd9e25feb37c9d2e466a76ffb39b971249b744..b2fc17b8faee27be6517e3ce2d4ab657e5942b40 100644 (file)
@@ -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/": {
index 4477da7a89ffeb071835ab137aa70f5d5205e05f..87fa839e2def32223c5416c402926f98a22995be 100644 (file)
@@ -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/": {
index b52304a2b9d3f61e8eee599c3324d80bc361b401..ef6c268c5ab38f335eff3fbcd72115f04ee96610 100644 (file)
@@ -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/": {
index dffdd162286304df462988bbec60e4e31fec68c2..6525fd50c3c16e184c9f67b1139555d19af0acc2 100644 (file)
@@ -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/": {
index 64ef7b22a27586d3a43d236241882ddd370dd951..b404ce5d8f99cb2319cb0b429a4f88905bcfd7e7 100644 (file)
@@ -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/": {
index f1ddc32595225c736cf78cc08eb5f1e88bb347b9..04e8ff82b09c0730a8350e8f3de352240f9a6122 100644 (file)
@@ -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 (file)
index 0000000..3efb1c4
--- /dev/null
@@ -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": {}}},
+                        }
+                    },
+                }
+            }
+        },
+    }
index f7f47a558eab2755ae4bf62442abbbaa12f74536..5072203712cf626ecabee7b9cf73e91aede1f503 100644 (file)
@@ -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/": {
index c6cdc60648c00feb8b2fd7edfa840fabe7ab62f2..a6e898c498c3eea530aa4ff5d82cdea4b6edc622 100644 (file)
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..9111fdb
--- /dev/null
@@ -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",
+                },
+            }
+        },
+    }
index c1cdbee2411dc6a5c09fac5e6ce4754d9437dea4..95542398e44f7011142f788fcb07e6aa6afa4fec 100644 (file)
@@ -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/": {
index fdaddd01878ebe48c28ad30dde1f36240b1636b7..d1388c367019ecc17cf1e2dcc87ba1f1dbe14d26 100644 (file)
@@ -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/": {
index 782c64a845ad81aaa73330bf223a4ab009bca881..313bb2a04aaca9c191c5ac93b2e3f0539a3c98f4 100644 (file)
@@ -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": {},
     }
index f5fd868eb7ce8dcf56bbf7740d3cfa28920441f0..cd9fc520e4165d21d5a15c0baf86909a54933c8b 100644 (file)
@@ -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/": {
index 52379c01e151118f7e7e43fde12bc3482fe6bd92..07e2d7d202c0d04a6bee9d8f186a0a456e8d7cca 100644 (file)
@@ -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/": {
index deb6b09101702b04ffdd0ffddc08de86b56f5201..f92c59015e099f0da6a3681f78c4f79a55e0620e 100644 (file)
@@ -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/": {
index 470956a77df7aae0b73a94e8a881acf45f946e80..3b88a38c28a7a3ea4ef5273119789e4d2ce8d7c0 100644 (file)
@@ -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/": {
index 76e44b5e59c3ab2208b3be45bd0f422baab6bad4..58dec5769d0d12eaa935443defc4e285d6e74a46 100644 (file)
@@ -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/": {
index cf8e203a0e1589f1aea151fcfbe7050e36be4372..30278caf86437351c78bfca5c7c1e17cef74b58e 100644 (file)
@@ -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/": {
index 497fc90242715a04277a7c5c5305b54821a35dd1..cf59d354cd753269e9417cef48643eef24ef9d2d 100644 (file)
@@ -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/": {
index 09fac44c4d9ddc5eaaa70430773036838a78ce07..a93ea8807eaa760a99d7061682de51d339d88265 100644 (file)
@@ -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/": {
index e90771f24b6d8c8edc0ccd36ce46f9bd6b5e4f64..91180d10973ce995a8554d6bcbb69cafe0e0a900 100644 (file)
@@ -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/": {
index ab0455bf5d3592e86a8d41e640d4b3dc0441f666..acbeaca769895a1ca7f5921e6b8077a6dba6e440 100644 (file)
@@ -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}": {
index 3401f2253410614ecf204f232b49f71e78821352..b9b58c96154c5ea82d3da742b4e20f456767418e 100644 (file)
@@ -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}": {
index 3c408449b81162433ae0289dc7febb03cc5728bf..6c2cba7e1299a41d77b3a29134a91a29428aca97 100644 (file)
@@ -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}": {
index 7fe58a99008eece9acbab692ed98629718c169cd..626637903f5a6f88e265aab3f521249d97a65c36 100644 (file)
@@ -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}": {
index b90c0a6c8ea9b81bd84de80b51c38a33639ee10c..b6fb2f39e112b6cac9e5c02382542ccdf8094bb9 100644 (file)
@@ -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}": {
index c41f554ba374bbc6a3af27a70a18600a0448ef8e..370ae0ff05790ef5046b6b13bfbc406cac2976b3 100644 (file)
@@ -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/": {
index dc8028f81199e17d678af00fc7d569a4b24098b2..1f76ef31467eaa1153ac4d4ecb7bceb2781cbcd3 100644 (file)
@@ -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/": {
index 496b95b797a2adb2689c3f5217930f800e78ae99..3a06b4bc7a68e92b04a203b9d2284d2b6b518592 100644 (file)
@@ -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/": {
index 2005e50433731dcc78f6495ff8e3bf58dce1cb50..1e6f9309370fea96b3e6a14af7521cdc77868fd8 100644 (file)
@@ -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/": {
index 8147d768e0f399a52b516d949ce065b19ba34d78..63524d291d81f6b33fd80328e2db1e906619d00e 100644 (file)
@@ -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/": {
index d6d69c1691232780a1b9712359c4a02d942e263f..164ec11930275a393fa91a3599b7654d1ad5a98b 100644 (file)
@@ -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/": {
index 3a53d422e0f1dc3a89e9029f96c0644e255c9426..2afaafd92ec150813388496f54399dc561f26ae5 100644 (file)
@@ -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/": {
index f00df28791810483aa153216efc6903537c2839b..fafd38337c9efc3094f532da3e198f6f3604b09a 100644 (file)
@@ -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/": {
index 895fb8e9f4e17ed851bbce8c30d3f46fede91df3..f3fb4752830cb74333e0902f5fce028374c7ff9c 100644 (file)
@@ -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/": {
index 4f4b1fd558b655331748be047b1a06ea818eb5dd..21f348f2b959ddcf565917adb5a0f5efcd9122bf 100644 (file)
@@ -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/": {
index d85bb623123e387a883ceb4adab292a5d050e677..f2c2a5a33e8b9392a54354e21d57a1aa5697d819 100644 (file)
@@ -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/": {
index 7bc020540ab247652e53f210f8c48f9d9f2c70c9..1436db384c99265e805b72ae6c57cc45cafe096d 100644 (file)
@@ -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/": {
index be5557f6ad3c6ec69936e194d3ee73b919791a7b..270763f1d1125cce2a0c4f5301b418518bff1358 100644 (file)
@@ -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/": {
index d9512e193f91fcafd6ad6ed46b276b41327dafd2..54839168395320c57862bc765e0d58fd1c7672c3 100644 (file)
@@ -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/": {
index b2a2c8d1d190df34970fae7ccff8648e76769bf1..e7d74515482a8ce1db6f9d3ef6165f7a1b516f7f 100644 (file)
@@ -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/": {
index 4a0b9e8b5fcee620b36d84e93a6e051807387acc..1ba1fdf618caf3a51a1de75f6ad2752988ce8116 100644 (file)
@@ -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/": {
index 71e4638ae4f5a4144ab103e6517a6fb6982d6e57..3432617481d8623d00294f2bacc601fb159e4684 100644 (file)
@@ -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/": {
index 4e90db358b4b693d7d2657435a23b1c6eee8f950..537d6325b35988f02ee1b7a3e40f00397cc16ca3 100644 (file)
@@ -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/": {
index 7686c07b39f42180a0bfaf8feae48ead23e14711..7bce7590c20b1759775b05ad5b1fe5ea0083cec7 100644 (file)
@@ -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/": {
index e739044a83fadb35127e36cd8bf3948dc680ecfa..2182e87b75434d1f7532e47150b31146de9f1211 100644 (file)
@@ -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/": {
index 73f0ba78b80fadbce0859e1f0733d1884105c4c5..344004d01b221b3226d55899b063edb7f05445fb 100644 (file)
@@ -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/": {
index e2c14999212bc4175922a6f694c4a3debe204659..5d4f6df3d0af94ac2c77f9b8c0c7931adc550311 100644 (file)
@@ -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/": {
index 07f30b7395b2af4c5f604d336b331e4f8fdca5bc..dad49fb12d5014d64d8e0bddbc9686e9edd9f49d 100644 (file)
@@ -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/": {
index 3269801efcd7bab714a3f436f655c119767e8fba..84c736180f9ce830c3b15fddbb8894e7678da731 100644 (file)
@@ -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/": {
index 4b6edfa066699c9bb82910bea985276d5c173b01..8ebe4eafdd6a30772ac2425c94cb78f773490ec7 100644 (file)
@@ -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/": {
index 0c34620e38d84138be7dca6143e11b60e2795e73..5da8b320be055f1ad5a4a8e1e9341fbf7195ab91 100644 (file)
@@ -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/": {
index 04442c76f451d4ef4925d8518e4df64c76862b0f..166f59b1a1a8b05b310a94296db55e2e8d9d836a 100644 (file)
@@ -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/": {
index f5249ef5bf3240b1ba38f9e75679c51e377a8e98..02ea604b2bbbff1ea79e385bbc84f5d9f2572f0c 100644 (file)
@@ -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/": {
index f690d107bae36e928171e8d04eb4ae301901a98a..c753e14d164bc0659147f86ba30ccb0e1ec97ce9 100644 (file)
@@ -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/": {
index 4af659a1113a1b23cd26aca2b73b4ab2a04f6abe..f02170814c9eb52c51e0a955a5f59276a7d24bd6 100644 (file)
@@ -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/": {
index 91dbc60b909a5f6898e12891b45a3500ad7c8172..acfb749ce2acceec5150cd670ee3a5caf36243bd 100644 (file)
@@ -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/": {
index 7c4ad326c4659bebecd63f73725b2b8c63667df6..36e5faac1815b1be598296aac09d19b32557175c 100644 (file)
@@ -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/": {
index 80c288ed6e3557645a81f611d99b4ecccdc82e0d..6eb2d55dc81e3bc92cf25f92a6bf15eba4c69d30 100644 (file)
@@ -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/": {
index 4dc1f752ce697460dc960f02a810f9f02f311b1d..4e3ef686946c2aeeb5e3f33bd4b639950ce7390b 100644 (file)
@@ -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/": {
index 6868be32847a2604d768b97c8caa0f18c5bc5cd1..65a8a9e61aa1af4e2124343c8fecb42d4b3f80a4 100644 (file)
@@ -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/": {
index ca1f62ea395216eb3b726866068ae0552d746254..52a8e1964807185aed89ffeea98dcebf86627adf 100644 (file)
@@ -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/": {
index e593ae75de43bc01d0ce7d17617dda80770da3de..6594e0116ce24f24e715785b71c7340a8cebb160 100644 (file)
@@ -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/": {
index bacd25b97e4801cfbcb3bdf80d6c0c6d8ab282ec..bfe964604ec1b06a4ed82d04627047cf71187ac0 100644 (file)
@@ -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/": {
index e2d69184b9d68412322e336aa1b7dbc8997f5ac8..85cd03a590e62360ba69c7bc9f9230c480f34c6b 100644 (file)
@@ -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/": {
index f199d4d2fd674a92d3946200d2f8e698a63bb4d3..0327a2db6c8272fd894f92a8b116f05c83e6b1fb 100644 (file)
@@ -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/": {
index 51fa8347057ae8750bb671e465dc3c069a6cc0cb..3aa68c6215e9558b66cbd01a5df14923661d9cdc 100644 (file)
@@ -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/": {
index 32b0289096ff5083d769687fb91fcbb813256c15..238bb39cd053632e2ab7da0a36f5f58348dbe9e3 100644 (file)
@@ -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/": {
index 721c97fb181e4c7b89cb36b6294df8abe97c4ebf..4a2a7abe95016f64458a0161a7dc6c7f2c6923a4 100644 (file)
@@ -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/": {
index 6b8abab1934eb02a2a22b23efbb5ab4667832ba4..347361344bad6190ee09c24210b687e7e1c4ae20 100644 (file)
@@ -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/": {
index 5862524add5f2c03e835cc00058e75b9ca2e02cb..e65a8823e72897a1df12e8a9571da4be9a89f987 100644 (file)
@@ -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/": {
index dcc44cf092e84f7bf845fa6254e59c98f384ed7a..be12656d2c460c407ed0ef1f6f30dcc00656e7f1 100644 (file)
@@ -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/": {
index f11e3698448dbe87fbf48b1f854b4ef4bc6eecf2..a5fcb3a94dbdc6405ad2f2a7ebdc0bd5243eb062 100644 (file)
@@ -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/": {
index 9b5e8681c61c19fa210d10418070ac28bb861b1f..6eacb2fcf20e8f0d3d187f8f2ca9619241b565ca 100644 (file)
@@ -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/": {
index 4a95cb2b5628f25be1d5671aeb9d1bfa4c7fbf6c..9cb0419a33ca821752f8a92277981a4ee875968a 100644 (file)
@@ -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/": {
index a055bc6885841d4d5966a5f6852eea585c39f971..8b8fe514ae48137ec30fbec2d0dca3668c01c3b6 100644 (file)
@@ -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/": {
index 8cb4ac208e9474d13fe25711dbfad1a4d7368178..01dc8e71ca3a94a95adac6407417e16e83477c4b 100644 (file)
@@ -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/": {
index 6ccb054b8336b013f0e08b13b8fc45f8ddd28810..eabd203456583dcdd2e037ad974b2fcc37f11c0d 100644 (file)
@@ -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": {
index ba4c0f2750619070d2b0fae5a976b427cc39185d..970ff5845000086c8b13d72112779a9569f034b7 100644 (file)
@@ -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": {
index d7c232e75118f70822ddf9bae85e4f26450d8d45..c7a39cc748323924d80a903709e8857ff9aac8eb 100644 (file)
@@ -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": {
index a89f1dad8b518ed28be1b7be21889795d2a29e10..f80d62572e29f9ffe0ba92121a95788bfbe7ad0d 100644 (file)
@@ -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": {
index 1f4ec9057f873689b3df373ac02ee6961a01307a..602147b1390d1098f54ac2ebb89240d1db95a72a 100644 (file)
@@ -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/": {
index 8cb7dc9cf412f39b44da72be731a443b9475e6bf..07af2920727610d1d74eb33d5663631e5ee76b20 100644 (file)
@@ -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}": {
index 2ba8143ba68ae8a7ee1e30f6386b8f9318287c38..90147fbdd2526244bc94c84c7e976386e01d29eb 100644 (file)
@@ -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}": {
index 97df0a238f59d8ea525ab05678393628d14b06d4..740a49590e5469627b0b4feeb898c87c17370cc2 100644 (file)
@@ -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}": {
index 76662f7937201d27003dbdd694ceac8cb3aa0980..e8c8946c543ef9e46d43337d34d1a976c4317c82 100644 (file)
@@ -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": {
index 1b1cf4175592e35d4bb9c79cf90607d61758fa8f..388e030bd580077438a5f3fc9d02d6d94292ea92 100644 (file)
@@ -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": {
index 3a759fde411063defb3fdb43837ac51de6090349..548a3dbd8710a90fd96037a298a176d3aa891da0 100644 (file)
@@ -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": {
index 07e84cc82ad4b1010b3eeaec85a07074186b08fe..075bb8079044bc759b0b82c52ba5f90b120e4afa 100644 (file)
@@ -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": {
index 784517d69ed9edae3f088fbf6088cb794f2ec996..dea136fb226c6b34064fc764b03c1781874465ef 100644 (file)
@@ -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,
index 222a4edfe8d5a6366182628ad3e8f747b0ca94d6..571feb19f8965e336d1f8f9e80d9da492ce9eff3 100644 (file)
@@ -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,
index 1eacd640af6cde9a0f60cd6efbbfffa558fff048..e25531794982b47d079231178486e4070b7fd365 100644 (file)
@@ -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,
index 632f2cbe0bc8cdf5ed7c8f4333183d5726b58d51..dafc5afade2cb8ce3371cb7de3ef0b4ba03960a4 100644 (file)
@@ -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,
index c99cb75c89beb6211a92c9fd19a6ff6001316377..29004218bb38b11b608e7942a8f43f40b93c4d91 100644 (file)
@@ -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,
index a7f55b78b292e98241cacbfc80b07da545f8fd82..417bed8f7a69a4d1f5431c1094fb1c19ec83b490 100644 (file)
@@ -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/": {
index fc48703aa020cfb2d3d28df8d54875417d925930..59460da7ff4f1309332a3ac9b8e251f4944e6052 100644 (file)
@@ -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/": {
index 345e0be0f3fb4f40350d9d31eab2e2c7c426bbb6..d8e71277367feb2f142815c3abde049740d955fa 100644 (file)
@@ -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/": {
index c10f928eb4800b987ad42a7a4b764dd0f4edcca3..cb5cdaa04d7947a1ea55f3aded38a4112dec0767 100644 (file)
@@ -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": {
index 41872fda03e1c68c71946884ba4ddf9f3f113175..26e68a0299bb26af427efbbfb0346f3b12d406e3 100644 (file)
@@ -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": {
index 02bd748c8cf3d609e3095255fe685d2f471402cb..1250d4afb314f654de85a268ab50df5fefddc787 100644 (file)
@@ -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": {
index 7e74afafb16fe23a415c3d77fdd11e71861e9b7c..b74cfdc54cdb5bcaca4438b97b2dea8c88ff1b67 100644 (file)
@@ -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": {
index a463751f5ee3e2c8a6418fcc5d0e79f543a73100..8a75d2321c26410f5a27a92e7ee6fa7c70b51a1c 100644 (file)
@@ -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": {
index ccb5b3c9f87568408395aac5acb3e1bdaa547194..4e4b6afe8003148fb84be9e52b49e968c0337174 100644 (file)
@@ -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": {
index e851f47fecd373c5a59d2e039b1174523976a63d..51cc8329a3eeabd3caac36a222c0a3a1f5cee57e 100644 (file)
@@ -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": {
index cca5819802ccc52f7a7d0615cbfe522f6ddb1441..b0d0fed1284daf3e08db83acc9c3766f0cbdce7c 100644 (file)
@@ -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": {
index eae851457568789642ff4523ba562abf356bbf7d..26deaaf3c2e4547493d0d7e1964ba34f3065b90c 100644 (file)
@@ -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": {
index cdbd8f75ec25c04ff16ada91f4df3d15b2497ab3..e93f34c3bc68785497f3a612b36cbdd3593291f3 100644 (file)
@@ -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": {
index 45b2a2341d7f008d00e5b798e3096cafd721738d..737a8548fde6899121c45c0fc22680f371ed0187 100644 (file)
@@ -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": {
index 73cbdc538d21bfb237b8969692266d69baf1a90f..dc459b6fd031385e1190ef55cb895bb81115cf02 100644 (file)
@@ -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": {
index 5f970ed013fb73e270039e7a2369e1e0216f72d3..52ddd938f992df5f2fa3c596453582bd5cbf65a8 100644 (file)
@@ -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": {
index 7d7a851acf65b082f6b703adfb83d2b5e220761a..52b22e5739a27863000fd1d7e756fc60359ee141 100644 (file)
@@ -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": {
index a2628f3c3bc0855c19b94c1d0c8e4794293a708c..d927940dab91504a71bcb284c21843a6a07e260d 100644 (file)
@@ -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/": {
index 02501b1a248f911bb69fdfd9fa923f31012b4013..08d7b353395e9a0ca73194754ac83e45cac1e5d4 100644 (file)
@@ -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/": {
index 67b92ea4a4012f7effcd9c9244cdcb23881ed09c..493fb3b6b938a4a94b3ce530e1652943cc791a16 100644 (file)
@@ -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/": {
index a2af20ea23194e78b2aedd802580639020e492a9..7b56685bc1bf7e31c8948589e4fc9d099fc90ca4 100644 (file)
@@ -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/": {
index 2f918cfd8bb497543c4c9dff9c771633cd4baf9e..43c2b272fe4f0081839a95f9ba6d5826312fe61f 100644 (file)
@@ -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/": {
index f2eefe41d03a429f44b651f818b94fb0730f1516..fd33517db807b66ee2786be6e08307aaf2881426 100644 (file)
@@ -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/": {
index d2470a2db9248a08a6bd62fe2710ca47912b5d63..ac6c427ca585144bc27de4d6b1146e9f400d31a2 100644 (file)
@@ -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/": {
index 00e9aec577900538c74846d4e28ec5c12d62f3c7..0790d207be10b752a921658bfd3f86bb9caa002d 100644 (file)
@@ -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": {
index 937ce75e428150cff05ce3dadd2b5d2d2d9c73f9..fe349808136cf16e4f2f3647e0a0baa866bc0af0 100644 (file)
@@ -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": {
             "/": {
index f3db70af2baca4bae608557765ce5264c5a4991a..471e896c93cac851b2fb16e1d8e1f13268c55d82 100644 (file)
@@ -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": {
             "/": {
index bc1e744328aef51c4960bfb7e832f97179cd9ddf..57a14b5748122d2d285c32a5f76cb299c0264943 100644 (file)
@@ -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/": {
index 988b920aa77ad4c4de0c864b904a5ffe992a5573..c2a37d3ddd20e7486ae7df49f0f71e7b6a7cabce 100644 (file)
@@ -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 (file)
index 0000000..a1c7b18
--- /dev/null
@@ -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"}},
+        },
+    }