For pydantic based models, enhance the Open API schema generation by differentiating between "validation" and "serialization" models.
The default mode used by the pydantic TypeAdapter when generating JSON schemas is a "validation" schema.
Add an additional option to the model_schema function in quart-schema/src/quart-schema/conversion.py called schema_mode that will execute the TypeAdapter schema generation in the selected mode. Keep the same default of "validation".
When generating Open API paths for response models specifically, change the schema_mode to "serialization" instead of "validation". This allows us to use models that have custom fields (e.g. computed fields or custom serialization logic) to be correctly converted to an Open API schema.
Added tests that demonstrate a very simple use case where you are using computed fields on a pydantic model:
from pydantic import BaseModel, computed_field
from quart import Quart
from quart_schema import QuartSchema, validate_response
class EmployeeWithComputedField(BaseModel):
first_name: str
last_name: str
@computed_field
@property
def full_name(self) -> str:
return f"{self.first_name} {self.last_name}"
async def test_response_model_with_computed_field():
"""
Test that routes returning a response model that has one or more computed fields have the
appropriate properties in the generated JSON schema.
"""
app = Quart(__name__)
QuartSchema(app, convert_casing=True)
@app.route("/")
@validate_response(EmployeeWithComputedField)
async def index() -> EmployeeWithComputedField:
return EmployeeWithComputedField(first_name="Jane", last_name="Doe")
test_client = app.test_client()
response = await test_client.get("/openapi.json")
schema = await response.get_json()
response_properties = schema["paths"]["/"]["get"]["responses"]["200"]["content"][
"application/json"
]["schema"]["properties"]
assert "firstName" in response_properties
assert "lastName" in response_properties
assert "fullName" in response_properties
The last assert (assert "fullName" in response_properties) will fail in the current version of quart schema as computed fields are only added to the JSON schema when the mode is set to "serialization" and the default for the pydantic TypeAdapter is "validation". This makes sense for data models being sent to the server where we can just re-generate the computed field so there is no need to include these fields in the incoming JSON. For responses however, it makes sense to include the computed field value as there may be custom serialization occurring that is non-trivial to re-implement on the client side.
Enhance pydantic model schema generation
model_schema
function inquart-schema/src/quart-schema/conversion.py
calledschema_mode
that will execute the TypeAdapter schema generation in the selected mode. Keep the same default of "validation".Added tests that demonstrate a very simple use case where you are using computed fields on a pydantic model:
The last assert (
assert "fullName" in response_properties
) will fail in the current version of quart schema as computed fields are only added to the JSON schema when the mode is set to "serialization" and the default for the pydanticTypeAdapter
is "validation". This makes sense for data models being sent to the server where we can just re-generate the computed field so there is no need to include these fields in the incoming JSON. For responses however, it makes sense to include the computed field value as there may be custom serialization occurring that is non-trivial to re-implement on the client side.