Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance Open API schema generation for pydantic response models #74

Merged
merged 2 commits into from
May 15, 2024

Conversation

bselman1
Copy link
Contributor

Enhance pydantic model schema generation

  • 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.

- For pydantic based models, enhance the open api schema generation by differntiating 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` called `schema_mode` that will execute the TypeAdapter schema generation in the selected mode.
- When generating Open API paths for response models, 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.
@pgjones pgjones merged commit 92d40f9 into pgjones:main May 15, 2024
@pgjones
Copy link
Owner

pgjones commented May 15, 2024

Thanks, see also for potential msgspec support jcrist/msgspec#686

@bselman1 bselman1 deleted the enhance-openapi-schema-generation branch May 15, 2024 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants