Flask Pydantic Spec
Flask Pydantic Spec is a Python library that simplifies the generation of OpenAPI documentation and the validation of Flask request/response payloads using Pydantic models and Python annotations. It provides decorators to integrate Pydantic validation directly into Flask route functions, enhancing API reliability and maintainability. The library is actively maintained, with frequent minor releases, and the current version is 0.8.7.
Common errors
-
ModuleNotFoundError: No module named 'flask_pydantic_spec'
cause The `flask-pydantic-spec` library has not been installed in your Python environment.fixRun `pip install flask-pydantic-spec`. -
pydantic.ValidationError: 1 validation error for RequestModelName
cause The incoming request data (query, body, headers, etc.) does not conform to the Pydantic model defined in your `@spec.validate` decorator.fixCheck the detailed error message for specific field violations. Adjust your incoming request data or refine your Pydantic model definition to match the expected format. -
TypeError: 'NoneType' object is not callable
cause This often occurs if `@spec.validate` is called with incorrect arguments, or if the `FlaskPydanticSpec` instance (`spec`) has not been properly initialized or registered with the Flask app (e.g., `spec.register(app)` is missing or called too late).fixEnsure `spec = FlaskPydanticSpec('app_name', app=app)` is called correctly and `spec.register(app)` is executed before routes are defined or accessed. Also, verify that the arguments passed to `@spec.validate` (e.g., `query`, `resp`) are correctly formed Pydantic models or `Response` objects. -
TypeError: BaseModel.__init__() got an unexpected keyword argument 'id'
cause This can happen if you are using Pydantic V1 models with `flask-pydantic-spec` v0.7.x, which only supported Pydantic V2. Or more generally, if you're mixing Pydantic V1 and V2 syntax when only one version is expected.fixIf on `flask-pydantic-spec` v0.7.x, you must use Pydantic V2 models. If on v0.8.0+, ensure consistency; if using V1 models, ensure they adhere to V1 syntax (e.g., `BaseModel` instead of `pydantic.v2.BaseModel`). Best practice is to upgrade `flask-pydantic-spec` to v0.8.0+ and ensure your Pydantic models are compatible with either V1 or V2 as appropriate for your project setup.
Warnings
- breaking Pydantic v1.x support was removed in `flask-pydantic-spec` v0.7.0, making it strictly Pydantic v2.x compatible. If you relied on Pydantic v1.x models, your application would break upon upgrading to v0.7.x.
- gotcha Blueprint support was added in `flask-pydantic-spec` v0.8.6. Prior versions do not natively support attaching `FlaskPydanticSpec` instances directly to Flask Blueprints.
- gotcha The order of decorators matters. Flask's `@app.route()` or `@blueprint.route()` decorator should typically be placed *before* `flask-pydantic-spec`'s `@spec.validate()` decorator.
- deprecated OpenAPI Specification 3.1.0 changed the schema keyword from 'definitions' to '$defs'. While `flask-pydantic-spec` v0.8.2 fixed this internally for its generated specs, older versions (specifically for 'v1 specs') might generate schemas that are not fully compliant with newer OpenAPI 3.1.0 tools or Swagger UI versions.
Install
-
pip install flask-pydantic-spec
Imports
- FlaskPydanticSpec
from flask_pydantic_spec import FlaskPydanticSpec
- Request
from flask_pydantic_spec import Request
- Response
from flask_pydantic_spec import Response
- Query
from flask_pydantic_spec import Query
- BaseModel
from pydantic import BaseModel
- Field
from pydantic import Field
Quickstart
from flask import Flask
from flask_pydantic_spec import FlaskPydanticSpec, Request, Response, Query
from pydantic import BaseModel, Field
# Define Pydantic models for request and response
class UserRequest(Request):
user_id: int = Field(Query, description="ID of the user")
class UserResponse(BaseModel):
id: int
name: str
email: str
app = Flask(__name__)
spec = FlaskPydanticSpec('flask-pydantic-spec', app=app)
spec.register(app)
@app.route('/user/<int:user_id>')
@spec.validate(
query=UserRequest,
resp=Response(HTTP_200=UserResponse)
)
def get_user(user_id):
# Access validated query parameters via spec.query
# Note: user_id from path param will override if name conflict
if spec.query.user_id != user_id:
print(f"Warning: Path ID {user_id} and Query ID {spec.query.user_id} mismatch.")
# In a real app, fetch user from DB
user_data = {"id": user_id, "name": f"User_{user_id}", "email": f"user{user_id}@example.com"}
return UserResponse(**user_data).model_dump()
# Example of OpenAPI documentation endpoint (auto-generated)
# Accessible at /swagger or /redoc by default
if __name__ == '__main__':
app.run(debug=True)