From 1726955d7f9442a6846be021115898650ea33c92 Mon Sep 17 00:00:00 2001 From: Hyunjae Woo Date: Sat, 26 Nov 2022 17:32:28 -0500 Subject: [PATCH 1/4] Add support for excluding none/unset fields in openapi schema --- fastapi/applications.py | 6 ++++++ fastapi/openapi/utils.py | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index 61d4582d2..f3d8cfba0 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -84,6 +84,8 @@ class FastAPI(Starlette): generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), + openapi_schema_exclude_unset: bool = False, + openapi_schema_exclude_none: bool = True, **extra: Any, ) -> None: self._debug: bool = debug @@ -105,6 +107,8 @@ class FastAPI(Starlette): self.extra = extra self.openapi_version = "3.0.2" self.openapi_schema: Optional[Dict[str, Any]] = None + self.openapi_schema_exclude_unset = openapi_schema_exclude_unset + self.openapi_schema_exclude_none = openapi_schema_exclude_none if self.openapi_url: assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" @@ -208,6 +212,8 @@ class FastAPI(Starlette): routes=self.routes, tags=self.openapi_tags, servers=self.servers, + exclude_unset=self.openapi_schema_exclude_unset, + exclude_none=self.openapi_schema_exclude_none, ) return self.openapi_schema diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 86e15b46d..abae7d094 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -402,6 +402,8 @@ def get_openapi( terms_of_service: Optional[str] = None, contact: Optional[Dict[str, Union[str, Any]]] = None, license_info: Optional[Dict[str, Union[str, Any]]] = None, + exclude_unset: bool = False, + exclude_none: bool = True, ) -> Dict[str, Any]: info: Dict[str, Any] = {"title": title, "version": version} if description: @@ -445,4 +447,9 @@ def get_openapi( output["paths"] = paths if tags: output["tags"] = tags - return jsonable_encoder(OpenAPI(**output), by_alias=True, exclude_none=True) # type: ignore + return jsonable_encoder( + OpenAPI(**output), + by_alias=True, + exclude_unset=exclude_unset, + exclude_none=exclude_none, + ) # type: ignore From bc42942cab9c95fa98669f30d74b357a4d5f2ebf Mon Sep 17 00:00:00 2001 From: Hyunjae Woo Date: Sat, 26 Nov 2022 17:33:05 -0500 Subject: [PATCH 2/4] Add tests for excluding none/unset fields in openapi schema --- tests/test_get_openapi_schema.py | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/test_get_openapi_schema.py diff --git a/tests/test_get_openapi_schema.py b/tests/test_get_openapi_schema.py new file mode 100644 index 000000000..6d89f320e --- /dev/null +++ b/tests/test_get_openapi_schema.py @@ -0,0 +1,57 @@ +from fastapi import FastAPI +from fastapi.testclient import TestClient + +app = FastAPI( + openapi_schema_exclude_unset=True, + openapi_schema_exclude_none=False, +) + + +@app.get( + "/items", + responses={ + 200: {"content": {"application/json": {"example": {"id": None, "value": 50}}}} + }, +) +def get_items(): + return {"id": "foo", "value": 50} + + +client = TestClient(app) + + +openapi_schema = { + "openapi": "3.0.2", + "info": {"title": "FastAPI", "version": "0.1.0"}, + "paths": { + "/items": { + "get": { + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {}, + "example": {"id": None, "value": 50}, + } + }, + } + }, + "summary": "Get Items", + "operationId": "get_items_items_get", + } + } + }, +} + + +def test_openapi_schema(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + assert response.json() == openapi_schema + + +def test_default_get_items(): + response = client.get("/items") + assert response.status_code == 200, response.text + assert response.json() == {"id": "foo", "value": 50} From b1f758153864f70b11cfdca7e15a10ac4b79e223 Mon Sep 17 00:00:00 2001 From: Hyunjae Woo Date: Sun, 27 Nov 2022 12:00:21 -0500 Subject: [PATCH 3/4] Fix linting --- fastapi/openapi/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index abae7d094..eeb444242 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -447,9 +447,9 @@ def get_openapi( output["paths"] = paths if tags: output["tags"] = tags - return jsonable_encoder( + return jsonable_encoder( # type: ignore OpenAPI(**output), by_alias=True, exclude_unset=exclude_unset, exclude_none=exclude_none, - ) # type: ignore + ) From ebb168a7a25fbeeb9d8007961f8f932faa967df2 Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Thu, 10 Jul 2025 11:15:23 +0200 Subject: [PATCH 4/4] Fix test (openapi version) --- tests/test_get_openapi_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_get_openapi_schema.py b/tests/test_get_openapi_schema.py index 6d89f320e..05fa8d2a0 100644 --- a/tests/test_get_openapi_schema.py +++ b/tests/test_get_openapi_schema.py @@ -21,7 +21,7 @@ client = TestClient(app) openapi_schema = { - "openapi": "3.0.2", + "openapi": "3.1.0", "info": {"title": "FastAPI", "version": "0.1.0"}, "paths": { "/items": {