Clarify Union documentation for response_model in python 3.10+ #16169
First Check
Commit to Help
Example Codefrom fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class BaseItem(BaseModel):
description: str
type: str
class CarItem(BaseItem):
type: str = "car"
class PlaneItem(BaseItem):
type: str = "plane"
size: int
items = {
"item1": {"description": "All my friends drive a low rider", "type": "car"},
"item2": {
"description": "Music is my aeroplane, it's my aeroplane",
"type": "plane",
"size": 5,
},
}
@app.get("/items/{item_id}", response_model=PlaneItem | CarItem)
async def read_item(item_id: str):
return items[item_id]DescriptionI noticed a possible contradiction in the FastAPI documentation regarding In the Python 3.10+ example in the "Union or anyOf" section, the documentation uses: @app.get(
"/items/{item_id}",
response_model=PlaneItem | CarItem,
)
async def read_item(item_id: str):
return items[item_id]However, immediately below, in the "Union in Python 3.10" section, the documentation says:
It then states that using: response_model=PlaneItem | CarItemwould result in an error because Python would try to perform an invalid operation between This seems contradictory because the Python 3.10+ example immediately above uses exactly I tested the example with a current Python/FastAPI setup, and: response_model=PlaneItem | CarItemworks as expected. My understanding is that in Python 3.10+, Could someone clarify whether the explanation in the "Union in Python 3.10" section is outdated, or whether there is some version-specific behavior that I am missing? If the explanation is outdated, I would be happy to submit a documentation PR to clarify the wording and make the two sections consistent. Relevant documentationThe current Python 3.10+ example uses: response_model=PlaneItem | CarItemwhile the following section says that the same syntax would result in an error and that I'm opening this discussion first to confirm the intended behaviour and documentation before proposing a PR. I'm happy to contribute a fix if needed Operating SystemmacOS Operating System DetailsmacOS Tahoe 26.6 FastAPI Version0.140.0 Pydantic Version2.13.4 Python Version3.10.20 Additional ContextNo response |
Replies: 2 comments 2 replies
|
Ran the exact tutorial003_py310.py on fastapi 0.140.0 / pydantic 2.13.4 / py3.12 and it just works: item1 returns the car, item2 the plane with size, both 200, and the OpenAPI response schema comes out as anyOf of the two models. So the note is outdated. On 3.10+ The "must use Union, |
|
You're reading it correctly: the code example is right and the surrounding prose is out of date. There's no bug in FastAPI here, just a documentation inconsistency. On Python 3.10+, The paragraph that says it "would get an error... we have to use So, to summarize:
This is already being corrected: the example was updated in #14932 and the prose fix is in PR #14939. Docs: https://fastapi.tiangolo.com/tutorial/extra-models/#union-or-anyof |
Ran the exact tutorial003_py310.py on fastapi 0.140.0 / pydantic 2.13.4 / py3.12 and it just works: item1 returns the car, item2 the plane with size, both 200, and the OpenAPI response schema comes out as anyOf of the two models. So the note is outdated. On 3.10+
PlaneItem | CarItemevaluates to atypes.UnionTypeat runtime (PEP 604), which is exactly why passing it as theresponse_modelvalue works.The "must use Union,
|would error" line is really pre-3.10 behavior, whereSomeClass | OtherClassraisesTypeError: unsupported operand type(s) for |(confirmed on 3.9.6). The example file itself got switched to the|form in the 3.10 typing-syntax upgrade, but the surrounding text stayed, s…