From 2f3aa866613b3cbd5684ff0ea2c3ed427739cbe6 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Tue, 13 May 2025 12:17:24 -0500 Subject: [PATCH 01/14] Add external_docs parameter to FastAPI class init external_docs is missing in FastAPI class. Added it to __init__ method to generate openapi spec --- fastapi/applications.py | 43 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/fastapi/applications.py b/fastapi/applications.py index 6d427cdc2..8e30cad22 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -810,6 +810,47 @@ class FastAPI(Starlette): """ ), ] = True, + external_docs: Annotated[ + Optional[Dict[str, Any]], + Doc( + """ + This field allows you to provide additional external documentation links + for an API operation or component. It’s an optional field and can be added + to an operation or a tag. If provided, it must be a dictionary containing: + + * `description`: A brief description of the external documentation, which may use + [CommonMark syntax](https://commonmark.org/) for rich text formatting. + * `url`: The URL pointing to the external documentation. The value **MUST** + be a valid URL format. + + **Example**: + + ```python + from fastapi import FastAPI + from typing import Dict, Any + from typing import Optional + from fastapi.openapi.models import Doc + from typing_extensions import Annotated + + external_docs: Annotated[Optional[Dict[str, Any]], Doc()] = { + "description": "Detailed API Reference", + "url": "https://example.com/api-docs", + } + + app = FastAPI(externalDocs=external_docs) + + ``` + + ### Explanation: + - `description`: Provides a short description explaining what this external documentation covers. + - `url`: Points to the full external documentation. + + **Notes**: + - This field is **optional**; if not included, no external documentation will be linked. + - You can use this feature to link to full API documentation, tutorials, or any other + """ + ), + ] = None, **extra: Annotated[ Any, Doc( @@ -838,6 +879,7 @@ class FastAPI(Starlette): self.swagger_ui_parameters = swagger_ui_parameters self.servers = servers or [] self.separate_input_output_schemas = separate_input_output_schemas + self.external_docs = external_docs self.extra = extra self.openapi_version: Annotated[ str, @@ -992,6 +1034,7 @@ class FastAPI(Starlette): tags=self.openapi_tags, servers=self.servers, separate_input_output_schemas=self.separate_input_output_schemas, + external_docs=self.external_docs, ) return self.openapi_schema From bb86eba0624072f4cb88de536f48fbec2dfc67a2 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Tue, 13 May 2025 12:21:14 -0500 Subject: [PATCH 02/14] Add external_docs parameters to get_openapi method The OpenAPI class is being instantiated without the externalDocs parameter. --- fastapi/openapi/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 808646cc2..b2913963e 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -489,6 +489,7 @@ def get_openapi( contact: Optional[Dict[str, Union[str, Any]]] = None, license_info: Optional[Dict[str, Union[str, Any]]] = None, separate_input_output_schemas: bool = True, + external_docs: Optional[Dict[str, Any]] = None, ) -> Dict[str, Any]: info: Dict[str, Any] = {"title": title, "version": version} if summary: @@ -566,4 +567,6 @@ def get_openapi( output["webhooks"] = webhook_paths if tags: output["tags"] = tags + if external_docs: + output["externalDocs"] = external_docs return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore From 1e7c36272986fae77b4e47f650cd7c6ffed83448 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 17:21:48 +0000 Subject: [PATCH 03/14] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20f?= =?UTF-8?q?ormat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/applications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 8e30cad22..fd2856321 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -838,7 +838,7 @@ class FastAPI(Starlette): } app = FastAPI(externalDocs=external_docs) - + ``` ### Explanation: From 7d7516879ab64e77939f73b5bbff886daf3433f2 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Tue, 13 May 2025 13:54:39 -0500 Subject: [PATCH 04/14] Update test_openapi_examples.py --- tests/test_openapi_examples.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py index b3f83ae23..77d275e97 100644 --- a/tests/test_openapi_examples.py +++ b/tests/test_openapi_examples.py @@ -5,7 +5,12 @@ from fastapi import Body, Cookie, FastAPI, Header, Path, Query from fastapi.testclient import TestClient from pydantic import BaseModel -app = FastAPI() +external_docs = { + "description": "External API documentation.", + "url": "https://docs.example.com/api-general" +} + +app = FastAPI(external_docs=external_docs) class Item(BaseModel): @@ -468,4 +473,8 @@ def test_openapi_schema(): }, } }, + "externalDocs": { + "description": "External API documentation.", + "url": "https://docs.example.com/api-general" + }, } From a28c2b7a21e637f63818f37a294ebd4b913a52fb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 13 May 2025 18:54:49 +0000 Subject: [PATCH 05/14] =?UTF-8?q?=F0=9F=8E=A8=20[pre-commit.ci]=20Auto=20f?= =?UTF-8?q?ormat=20from=20pre-commit.com=20hooks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_openapi_examples.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py index 77d275e97..7c4518bd8 100644 --- a/tests/test_openapi_examples.py +++ b/tests/test_openapi_examples.py @@ -7,7 +7,7 @@ from pydantic import BaseModel external_docs = { "description": "External API documentation.", - "url": "https://docs.example.com/api-general" + "url": "https://docs.example.com/api-general", } app = FastAPI(external_docs=external_docs) @@ -475,6 +475,6 @@ def test_openapi_schema(): }, "externalDocs": { "description": "External API documentation.", - "url": "https://docs.example.com/api-general" + "url": "https://docs.example.com/api-general", }, } From 7001d1b53c991b1ff41ee54f13357071513c48b1 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Wed, 14 May 2025 15:28:08 -0500 Subject: [PATCH 06/14] Update applications.py --- fastapi/applications.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index fd2856321..c139e7f3c 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -810,7 +810,7 @@ class FastAPI(Starlette): """ ), ] = True, - external_docs: Annotated[ + openapi_external_docs: Annotated[ Optional[Dict[str, Any]], Doc( """ @@ -837,7 +837,7 @@ class FastAPI(Starlette): "url": "https://example.com/api-docs", } - app = FastAPI(externalDocs=external_docs) + app = FastAPI(openapi_external_docs=external_docs) ``` @@ -879,7 +879,7 @@ class FastAPI(Starlette): self.swagger_ui_parameters = swagger_ui_parameters self.servers = servers or [] self.separate_input_output_schemas = separate_input_output_schemas - self.external_docs = external_docs + self.openapi_external_docs = openapi_external_docs self.extra = extra self.openapi_version: Annotated[ str, @@ -1034,7 +1034,7 @@ class FastAPI(Starlette): tags=self.openapi_tags, servers=self.servers, separate_input_output_schemas=self.separate_input_output_schemas, - external_docs=self.external_docs, + external_docs=self.openapi_external_docs, ) return self.openapi_schema From e6836b44936006a93fd1e3f32d4e36709adb64e0 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Wed, 14 May 2025 15:29:04 -0500 Subject: [PATCH 07/14] Update test_openapi_examples.py --- tests/test_openapi_examples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py index 7c4518bd8..85b74aa43 100644 --- a/tests/test_openapi_examples.py +++ b/tests/test_openapi_examples.py @@ -10,7 +10,7 @@ external_docs = { "url": "https://docs.example.com/api-general", } -app = FastAPI(external_docs=external_docs) +app = FastAPI(openapi_external_docs=external_docs) class Item(BaseModel): From e58fdd9ae598d3b59b160aaf5ae08a5ad593f3ec Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:40:21 -0500 Subject: [PATCH 08/14] Update fastapi/applications.py Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> --- fastapi/applications.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index c139e7f3c..1fad0b68d 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -814,9 +814,8 @@ class FastAPI(Starlette): Optional[Dict[str, Any]], Doc( """ - This field allows you to provide additional external documentation links - for an API operation or component. It’s an optional field and can be added - to an operation or a tag. If provided, it must be a dictionary containing: + This field allows you to provide additional external documentation links. + If provided, it must be a dictionary containing: * `description`: A brief description of the external documentation, which may use [CommonMark syntax](https://commonmark.org/) for rich text formatting. From eb8086ae9d89eed0c7e750cdc70c8879a50a2cc7 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:40:43 -0500 Subject: [PATCH 09/14] Update fastapi/applications.py Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> --- fastapi/applications.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 1fad0b68d..c3863830f 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -826,18 +826,13 @@ class FastAPI(Starlette): ```python from fastapi import FastAPI - from typing import Dict, Any - from typing import Optional - from fastapi.openapi.models import Doc - from typing_extensions import Annotated - external_docs: Annotated[Optional[Dict[str, Any]], Doc()] = { + external_docs = { "description": "Detailed API Reference", "url": "https://example.com/api-docs", } app = FastAPI(openapi_external_docs=external_docs) - ``` ### Explanation: From 1c6300f62fc2c4123370e71d6f20bcc5ab10fd49 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:41:19 -0500 Subject: [PATCH 10/14] Update fastapi/applications.py Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> --- fastapi/applications.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index c3863830f..a91272ff0 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -834,14 +834,6 @@ class FastAPI(Starlette): app = FastAPI(openapi_external_docs=external_docs) ``` - - ### Explanation: - - `description`: Provides a short description explaining what this external documentation covers. - - `url`: Points to the full external documentation. - - **Notes**: - - This field is **optional**; if not included, no external documentation will be linked. - - You can use this feature to link to full API documentation, tutorials, or any other """ ), ] = None, From 19a6c37e1f1a21fcc8ba471b1c84da54270cf110 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 17 Jul 2025 18:51:09 -0500 Subject: [PATCH 11/14] Update applications.py remove https://commonmark.org/ reference from openapi_external_docs documentation --- fastapi/applications.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index a91272ff0..3860077cc 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -817,8 +817,7 @@ class FastAPI(Starlette): This field allows you to provide additional external documentation links. If provided, it must be a dictionary containing: - * `description`: A brief description of the external documentation, which may use - [CommonMark syntax](https://commonmark.org/) for rich text formatting. + * `description`: A brief description of the external documentation. * `url`: The URL pointing to the external documentation. The value **MUST** be a valid URL format. From fbcee28d5c7aaceb2dfe4e2ed24feb9dc0bf64e3 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 31 Jul 2025 20:14:16 -0500 Subject: [PATCH 12/14] Update main.py --- tests/main.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/main.py b/tests/main.py index 6927eab61..2f1d61711 100644 --- a/tests/main.py +++ b/tests/main.py @@ -3,7 +3,12 @@ from typing import FrozenSet, List, Optional from fastapi import FastAPI, Path, Query -app = FastAPI() +external_docs = { + "description": "External API documentation.", + "url": "https://docs.example.com/api-general", +} + +app = FastAPI(openapi_external_docs=external_docs) @app.api_route("/api_route") From 39db7382c9ebed879f95011eeda8c35ec8ebe853 Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 31 Jul 2025 20:19:24 -0500 Subject: [PATCH 13/14] Update test_application.py --- tests/test_application.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_application.py b/tests/test_application.py index a7d50ea72..8f1b0a18d 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -58,6 +58,10 @@ def test_openapi_schema(): assert response.json() == { "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, + "externalDocs": { + "description": "External API documentation.", + "url": "https://docs.example.com/api-general", + }, "paths": { "/api_route": { "get": { From a53fd4f29dc79151b369ddf888667d7d2fb0dfad Mon Sep 17 00:00:00 2001 From: Carlos Mario Toro <41237977+cmtoro@users.noreply.github.com> Date: Thu, 31 Jul 2025 20:22:37 -0500 Subject: [PATCH 14/14] Update test_openapi_examples.py --- tests/test_openapi_examples.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/tests/test_openapi_examples.py b/tests/test_openapi_examples.py index 85b74aa43..b3f83ae23 100644 --- a/tests/test_openapi_examples.py +++ b/tests/test_openapi_examples.py @@ -5,12 +5,7 @@ from fastapi import Body, Cookie, FastAPI, Header, Path, Query from fastapi.testclient import TestClient from pydantic import BaseModel -external_docs = { - "description": "External API documentation.", - "url": "https://docs.example.com/api-general", -} - -app = FastAPI(openapi_external_docs=external_docs) +app = FastAPI() class Item(BaseModel): @@ -473,8 +468,4 @@ def test_openapi_schema(): }, } }, - "externalDocs": { - "description": "External API documentation.", - "url": "https://docs.example.com/api-general", - }, }