How to validate request data¶
Flask-Jeroboam validates incoming requests automatically based on your function signatures and Pydantic models. This guide shows common patterns for validating different types of request data.
Simple scalar parameters¶
For single values, use type hints directly on function arguments:
@app.get("/items")
def get_items(page: int = 1, limit: int = 10):
# page and limit are automatically validated as integers
return fetch_items(page, limit)
Try passing invalid values to see automatic error responses:
$ curl "http://localhost:5000/items?page=abc"
{"detail":[{"loc":["query","page"],"msg":"Input should be a valid integer","type":"int_parsing"}]}
Query vs body parameters¶
By default, GET requests use query parameters and POST requests use body parameters. If you need to mix them, be explicit:
from flask_jeroboam import Query, Body
@app.post("/items")
def create_item(
# Query parameter (explicit)
category: str = Query(...),
# Body parameters (implicit for POST)
name: str = Body(...),
description: str = Body(...)
):
return {"name": name, "description": description, "category": category}
Using Pydantic models¶
For complex structures, use Pydantic models. This adds schema validation:
from pydantic import BaseModel, Field
class ItemCreate(BaseModel):
name: str
description: str = None
price: float = Field(..., gt=0) # Must be greater than 0
@app.post("/items")
def create_item(item: ItemCreate):
# item is validated and provides IDE autocomplete
return {"created": item.name}
Field constraints¶
Add validation rules directly in your model:
from pydantic import Field, EmailStr
class UserCreate(BaseModel):
email: EmailStr # Automatically validated as email
age: int = Field(..., ge=18, le=120) # 18-120 range
username: str = Field(..., min_length=3, max_length=20)
bio: str = Field("", max_length=500)
Try creating a user with invalid data:
$ curl -X POST http://localhost:5000/users \
-H "Content-Type: application/json" \
-d '{"email": "not-an-email", "age": 15}'
{"detail":[{"loc":["body","email"],"msg":"value is not a valid email address"},{"loc":["body","age"],"msg":"Input should be greater than or equal to 18"}]}
Path parameters¶
Path parameters are detected automatically from the URL rule. No extra work needed:
@app.get("/items/<int:item_id>")
def get_item(item_id: int):
# item_id is automatically validated and injected
return fetch_item(item_id)
Conditional validation¶
Use Pydantic’s validators to add custom logic:
from pydantic import BaseModel, field_validator
class EventCreate(BaseModel):
name: str
start_date: str
end_date: str
@field_validator('end_date')
@classmethod
def end_after_start(cls, v, info):
if info.data.get('start_date') and v < info.data.get('start_date'):
raise ValueError('end_date must be after start_date')
return v
This ensures end_date is always after start_date, even if both dates are individually valid.
Optional fields¶
Make fields optional by using None as default:
from typing import Optional
class ItemFilter(BaseModel):
category: Optional[str] = None
min_price: Optional[float] = None
max_price: Optional[float] = None
@app.get("/items")
def search_items(filter: ItemFilter):
# All fields are optional
return search(filter)