Separate I/O schemas inconsistencies #10697
-
First Check
Commit to Help
Example Codefrom decimal import Decimal
import pytest
from fastapi import FastAPI, status
from pydantic import BaseModel, ConfigDict
def get_app(
separate_input_output_schemas: bool,
json_schema_serialization_defaults_required: bool,
):
class Model(BaseModel):
model_config = ConfigDict(
json_schema_serialization_defaults_required=json_schema_serialization_defaults_required,
)
foo: int = 42
bar: Decimal # Decimal has different schemas for input (validation) and output (serialization)
app = FastAPI(separate_input_output_schemas=separate_input_output_schemas)
@app.post(
"/",
responses={
status.HTTP_402_PAYMENT_REQUIRED: {
"model": Model,
},
},
)
def root(model: Model) -> Model:
return model
return app
@pytest.mark.parametrize("json_schema_serialization_defaults_required", [True, False])
def test_suppress_separate_io_models(
json_schema_serialization_defaults_required: bool,
):
"""
Case #1 - this works fine, skip this function if you want.
Setting separate_input_output_schemas to False
suppresses generating separate schemas for input and output
regardless of json_schema_serialization_defaults_required value.
"""
app = get_app(
separate_input_output_schemas=False,
json_schema_serialization_defaults_required=json_schema_serialization_defaults_required,
)
schema = app.openapi()
assert "Model" in schema["components"]["schemas"]
assert "Model-Input" not in schema["components"]["schemas"]
assert "Model-Output" not in schema["components"]["schemas"]
@pytest.mark.parametrize("json_schema_serialization_defaults_required", [True, False])
def test_separate_io_models(
json_schema_serialization_defaults_required: bool,
):
"""
Case #2
Setting separate_input_output_schemas to True
generates separate schemas for input and output
regardless of json_schema_serialization_defaults_required value (because we have the Decimal field),
but (bug?) generates the "Input" schema for the custom response.
"""
app = get_app(
separate_input_output_schemas=True,
json_schema_serialization_defaults_required=json_schema_serialization_defaults_required,
)
schema = app.openapi()
assert "Model" not in schema["components"]["schemas"]
assert "Model-Input" in schema["components"]["schemas"]
assert "Model-Output" in schema["components"]["schemas"]
# Separate Input model for the request
assert (
"Model-Input"
in schema["paths"]["/"]["post"]["requestBody"]["content"]["application/json"]["schema"]["$ref"]
)
# Separate Output model for the 200 response
assert (
"Model-Output"
in schema["paths"]["/"]["post"]["responses"]["200"]["content"]["application/json"]["schema"]["$ref"]
)
# Separate Output model for the 402 response
# This fails!
assert (
"Model-Output"
in schema["paths"]["/"]["post"]["responses"]["402"]["content"]["application/json"]["schema"]["$ref"]
)DescriptionI think I've spotted two issues regarding the separate Input and Output OpenAPI schemas topic.
Operating SystemmacOS Operating System DetailsNo response FastAPI Version0.104.1 Pydantic Version2.5.1 Python VersionPython 3.10.9 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
|
@Kludex sorry for pinging you directly. Is there any chance you could turn this into an issue? |
Beta Was this translation helpful? Give feedback.
-
|
Issue 1. is addressed in this PR #11517 |
Beta Was this translation helpful? Give feedback.
-
|
In case someone runs into this issue too:
If your model is being used only in the context of responses, you can force the mode (so the schema is being rendered properly) by adding a config option on your model, like this: model_config = ConfigDict(
json_schema_mode_override="serialization",
) |
Beta Was this translation helpful? Give feedback.
-
|
For what it's worth, it looks like Pydantic added an internal issue pydantic/pydantic#8413 soon after pydantic/pydantic#7275 was merged, which seems to be calling attention to your Issue (2) in your original post—fields with defaults confusingly end up as not required in the serialization schema. |
Beta Was this translation helpful? Give feedback.
-
|
This has been fixed 🎉 |
Beta Was this translation helpful? Give feedback.
This has been fixed 🎉
Works fine in current versions (FastAPI 0.115.12, Pydantic 2.11.5)