Skip to course content
Free generative AI app course

Generative AI Application Development with Python

Unit 05.02: Validating values, not just structure

Parsing gets you a dict. Validation gets you a dict you can rely on.

Types, allowed values, patterns

Four candidates against a schema with literals and a field pattern.

The code validates each.

from pydantic import BaseModel, Field, ValidationError
from typing import Literal


class Triage(BaseModel):
    category: Literal["billing", "technical", "account", "other"]
    urgency: Literal["low", "medium", "high"]
    account_id: str = Field(pattern=r"^ACC-\d+$")


for raw in [
    {"category": "billing", "urgency": "high", "account_id": "ACC-1187"},
    {"category": "Billing Dept", "urgency": "high", "account_id": "ACC-1187"},
    {"category": "billing", "urgency": "critical", "account_id": "ACC-1187"},
    {"category": "billing", "urgency": "high", "account_id": "1187"},
]:
    try:
        print(f"OK    {Triage(**raw)}")
    except ValidationError as exc:
        e = exc.errors()[0]
        print(f"FAIL  {str(raw)[:52]:54} {e['loc'][0]}: {e['type']}")

# All four parse as JSON. Three have values no downstream code can handle, and
# a parser accepts every one of them. Parsing gets you a dict; validation gets
# you a dict you can rely on.

All four parse as JSON. Three carry values no downstream code can handle: a plausible label outside the allowed set, an invented urgency level, and a malformed id.

The first of those is what model drift looks like. "Billing Dept" is a reasonable thing to produce and is not a value your router recognises.

The mistake this prevents

The mistake is checking with if "category" in result. It catches the missing field and neither of the others, and it grows into a page of hand-written checks that drift out of sync with what the consumer expects.

Takeaway

Validate types, allowed values and formats with a declared schema. A successful parse tells you the shape was JSON, not that the content is usable.