Replies: 2 comments 1 reply
-
|
Minimized code example: from fastapi import FastAPI
from pydantic import BaseModel, Field
class A(BaseModel):
name: str = ""
class B(BaseModel):
name: str
a: A = Field(exclude=True)
app = FastAPI()
@app.get("/")
async def get_b() -> B:
return B(name="example", a=A(name="example"))
def test_a_not_in_schemas():
openapi = app.openapi()
assert "A" not in openapi["components"]["schemas"].keys()
# AssertionError: assert 'A' not in dict_keys(['A', 'B'])So, |
Beta Was this translation helpful? Give feedback.
-
|
Using your minimized code example, I ran And the associated PR: #14168 I got a look at
Applying the following patch makes @YuriiMotov code example works: diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py
index 29606b9f..51540e25 100644
--- a/fastapi/_compat/v2.py
+++ b/fastapi/_compat/v2.py
@@ -375,6 +375,7 @@ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]:
return [
ModelField(field_info=field_info, name=name)
for name, field_info in model.model_fields.items()
+ if not field_info.exclude
]The issue lies in how For now, I'm monkey patching FastAPI like that: def monkey_patch_fastapi_openapi_exclude() -> None:
import logging
import fastapi._compat.v2
from pydantic import BaseModel
def get_model_fields(model: type[BaseModel]) -> list[fastapi._compat.v2.ModelField]:
return [
fastapi._compat.v2.ModelField(field_info=field_info, name=name)
for name, field_info in model.model_fields.items()
if not field_info.exclude
]
fastapi._compat.v2.get_model_fields = get_model_fields
logging.info("fastapi._compat.v2.get_model_fields is monkey patched to support Field(exclude=True)")
monkey_patch_fastapi_openapi_exclude() |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
First Check
Commit to Help
Example Code
Description
Running the example provide will result in the following output.
Note that
fieldsis set to beexclude=Trueand it is indeed excluded from theDatabaseCollectionInfoschema, BUT theDatabaseFieldInfois still rendered in the components list even though it is never used in the API footprint.This is a regression and was working in
0.118.3, but is no longer working in0.120.2{ "openapi": "3.1.0", "info": { "title": "Minimal FastAPI App", "version": "1.0.0" }, "paths": { "/collection": { "get": { "summary": "Get Collection Info", "operationId": "get_collection_info_collection_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DatabaseCollectionInfo" } } } } } } } }, "components": { "schemas": { "DatabaseCollectionInfo": { "properties": { "name": { "type": "string", "title": "Name", "description": "Name of the Database collection" }, "description": { "type": "string", "title": "Description", "description": "Description of the Database collection", "default": "" } }, "type": "object", "required": [ "name" ], "title": "DatabaseCollectionInfo" }, "DatabaseFieldInfo": { "properties": { "name": { "type": "string", "title": "Name", "description": "Name of the field in the Database collection", "default": "" } }, "type": "object", "title": "DatabaseFieldInfo" } } } }Operating System
macOS
Operating System Details
No response
FastAPI Version
0.120.2
Pydantic Version
2.12.3
Python Version
Python 3.13.1
Additional Context
Why is this problematic? Setting
exclude=Trueis useful when you need to prevent implementation details from being exposed to the outside world, e.g. via the OpenAPI spec.But in this regression, even though
excludeis set and it is indeed excluded from the parent schema, the nested schemas associated with it are still exposed and can leak details that the API author does not want to expose in the spec, even if the data is not returned by the API.Beta Was this translation helpful? Give feedback.
All reactions