pgjones / quart-schema

Quart-Schema is a Quart extension that provides schema validation and auto-generated API documentation.
MIT License
76 stars 24 forks source link

Enhance Open API schema generation for pydantic response models #74

Closed bselman1 closed 3 months ago

bselman1 commented 6 months ago

Enhance pydantic model schema generation

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.

pgjones commented 3 months ago

Thanks, see also for potential msgspec support https://github.com/jcrist/msgspec/issues/686