Why Pydantic with Nexios?
- Flexible Validation: Use Pydantic when you need it, without being forced into a type-hinted architecture
- Clean Error Handling: Built-in error formatting that works out of the box
- Performance: Efficient validation with minimal overhead
- Optional Typing: Add type safety where it matters most
Getting Started
Installation
First, install Pydantic:
bash
pip install pydanticBasic Usage
python
from nexios import NexiosApp
from pydantic import BaseModel
from datetime import datetime
app = NexiosApp()
class UserCreate(BaseModel):
username: str
email: str
signup_date: datetime = None
age: int = None
@app.post("/users")
async def create_user(request, response):
# Manually validate with Pydantic
data = await request.json
user = UserCreate(**data)
# Your business logic here
return response.json(user.dict())Error Handling
Nexios provides a built-in error handler for Pydantic validation errors with multiple formatting options:
python
from nexios.utils.pydantic import add_pydantic_error_handler
# Add the error handler to your app
add_pydantic_error_handler(app, style="list", status_code=422)Error Formats
Choose from three different error formats:
Flat Format
json{ "error": "Validation Error", "errors": { "username": "field required", "email": "invalid email format" } }List Format
json{ "error": "Validation Error", "errors": [ {"field": "username", "message": "field required"}, {"field": "email", "message": "invalid email format"} ] }Nested Format (default)
json{ "error": "Validation Error", "errors": { "user": { "username": "field required", "profile": { "email": "invalid email format" } } } }
Advanced Usage
Nested Models
python
class Profile(BaseModel):
bio: str
website: str = None
class UserUpdate(BaseModel):
username: str
profile: Profile
@app.put("/users/{user_id}")
async def update_user(request, response, user_id: str):
data = await request.json
update = UserUpdate(**data)
# Update user logic here
return response.json(update.dict())Custom Validators
python
from pydantic import validator
class Item(BaseModel):
name: str
price: float
@validator('price')
def price_must_be_positive(cls, v):
if v <= 0:
raise ValueError('Price must be positive')
return vWhy Nexios is More Flexible
No Type Hinting Required
- Use Pydantic where it makes sense
- Keep other parts of your application dynamic
- Gradually adopt type safety as needed
No Framework Lock-in
- Pydantic is optional, not enforced
- Easy to remove or replace if needed
- No tight coupling with the framework
Progressive Enhancement
- Start simple, add validation later
- Mix and match validation approaches
- Evolve your codebase at your own pace
Best Practices
Use Pydantic for:
- API request/response validation
- Configuration management
- Data serialization/deserialization
- Complex data transformations
Keep it simple when:
- Building prototypes
- Internal APIs
- Simple endpoints
Consider using type hints for:
- Public APIs
- Critical business logic
- Team projects with multiple developers
Example Project Structure
myapp/
models/
__init__.py
user.py # Pydantic models
schemas.py # Request/response schemas
routes/
__init__.py
users.py # Route handlers
main.py # App setup and configuration