Skip to main content

Pydantic for JSON Validation in Python

Β· 6 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

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​

FeatureWhy it matters
Type CoercionIt will smartly convert the string "150.5" into the float 150.5 if it can.
Clear ErrorsGives you exact JSON paths to the broken fields so frontend devs can fix their bugs.
IDE SupportBecause it uses type hints, VS Code and PyCharm will give you autocomplete for all your data.
FastAPI CorePydantic is the engine that powers FastAPI, one of Python's most popular web frameworks.

πŸ“š Sources & Technical Refs​