- Keeps
main.pyfocused on routing and app wiring. - Promotes reuse of schema classes across endpoints (create, update, responses).
- Simplifies tests, documentation, and OpenAPI generation.
Quick example: inline schema (before extraction)
This works for tiny examples but becomes hard to maintain as your API grows.schemas.py so you can clearly separate request shapes (what clients send) and response shapes (what your API returns).
Create schemas.py
- Define base fields once and reuse them with inheritance.
- Create distinct classes for create/update requests if input requirements differ.
- Add
orm_mode = Trueon response schemas to allow Pydantic to read SQLAlchemy ORM objects.
schemas.py:
Using the schemas in main.py
Import theschemas module and reference specific classes in endpoint signatures. Using response_model enforces the output shape and adds it to the generated OpenAPI docs.
App setup (assumes models.py and database.py exist):
PostOut):
PostCreate; response uses PostOut):
When you use
response_model with SQLAlchemy ORM objects, set orm_mode = True on the response Pydantic model (as shown in PostOut). This tells Pydantic to read attributes from ORM instances instead of expecting plain dicts.When to create multiple request schemas
Create separate request schemas when permissions or allowed fields differ between operations:- POST: full creation input (e.g.,
PostCreate). - PUT/PATCH: partial updates or restricted updates (e.g.,
PostUpdatewith optional fields). - Separate schemas also make validation rules explicit and reduce accidental field overwrite.
