Pydantic for JSON Validation in Python
In our last article(python simpleeval examples), we built a dynamic rules engine using simpleeval. But there is a golden rule in software engineering: Garbage In, Garbage Out.
If your rules engine expects a checkout cart to have a cart_total (a number) and a user_role (a string), but the frontend accidentally sends {"cart_total": "free", "role": null}, your engine will crash. Before untrusted JSON data ever reaches your core logic, it needs to pass through a strict gatekeeper. In modern Python, that gatekeeper is Pydantic.
ποΈ 1. What is Pydantic?β
Pydantic is a data validation library that uses standard Python type hints to enforce data schemas. Unlike older validation libraries where you had to write complex validation rules by hand, Pydantic just looks at your classes and does the heavy lifting for you.
Installation:
pip install pydantic
π» 2. The Basic Model: Defining Your Schemaβ
Let's build a schema for the checkout data we used in our simpleeval rules engine. We do this by inheriting from Pydantic's BaseModel.
from pydantic import BaseModel, ValidationError
from typing import Optional
class CheckoutContext(BaseModel):
cart_total: float
user_role: str
item_count: int
# Optional means this field can be missing or None
coupon_code: Optional[str] = None
# 1. PERFECT DATA: Pydantic parses it seamlessly
raw_json_string = '{"cart_total": 150.00, "user_role": "VIP", "item_count": 5}'
validated_data = CheckoutContext.model_validate_json(raw_json_string)
print(f"β
Validated Total: ${validated_data.cart_total}")
print(f"β
Python Type: {type(validated_data.cart_total)}") # <class 'float'>
π 3. Catching Bad Data (Validation Errors)β
What happens if the API sends a string instead of an integer, or completely forgets a required field? Pydantic catches it and provides incredibly detailed error messages.
# BAD DATA: 'item_count' is missing, 'cart_total' is text
bad_data = {
"cart_total": "one hundred",
"user_role": "VIP"
}
try:
# We use model_validate for Python dictionaries
bad_checkout = CheckoutContext.model_validate(bad_data)
except ValidationError as e:
print("β Validation Failed!")
# Pydantic gives you a structured list of exactly what went wrong
for error in e.errors():
field = error['loc'][0]
message = error['msg']
print(f" - Field '{field}': {message}")
# Output:
# β Validation Failed!
# - Field 'cart_total': Input should be a valid number, unable to parse string as a number
# - Field 'item_count': Field required
π§ 4. Advanced Validation: Custom Rulesβ
Sometimes, types aren't enough. An item_count of -5 is technically an integer, but it makes no sense for a shopping cart. We can use the @field_validator decorator to enforce business logic.
from pydantic import BaseModel, field_validator, ValidationError
class StrictCheckout(BaseModel):
cart_total: float
item_count: int
@field_validator('item_count')
@classmethod
def check_item_count(cls, value):
if value <= 0:
raise ValueError("Item count must be at least 1")
return value
try:
StrictCheckout(cart_total=50.0, item_count=-2)
except ValidationError as e:
print(e.errors()[0]['msg'])
# Output: Value error, Item count must be at least 1
π 5. Integrating with simpleevalβ
Once Pydantic has sanitized your data, you can safely pass it to other parts of your app. Pydantic v2 includes a .model_dump() method to instantly convert your pristine object back into a standard Python dictionary (which simpleeval loves).
# Assuming 'validated_data' is our pristine Pydantic object from Step 2
clean_dict = validated_data.model_dump()
# Now it is 100% safe to feed into simpleeval
# is_match = simple_eval(rule_string, names=clean_dict)
π Summary: Why Pydantic Rulesβ
| Feature | Why it matters |
|---|---|
| Type Coercion | It will smartly convert the string "150.5" into the float 150.5 if it can. |
| Clear Errors | Gives you exact JSON paths to the broken fields so frontend devs can fix their bugs. |
| IDE Support | Because it uses type hints, VS Code and PyCharm will give you autocomplete for all your data. |
| FastAPI Core | Pydantic is the engine that powers FastAPI, one of Python's most popular web frameworks. |
π Sources & Technical Refsβ
- [1.1] Pydantic Docs: Models (BaseModel) - Official guide on declaring and using models.
- [1.2] Pydantic Docs: Validators - How to write custom validation logic.
- [2.1] Real Python: Data Validation with Pydantic - A comprehensive deep-dive tutorial.
