FastAPI Data Validation

Pydantic is the library that powers all data checking in FastAPI. It reads the type hints you write in Python and enforces them on every piece of incoming data. Bad data never reaches your business logic — Pydantic stops it at the door.

Think of Pydantic as a Customs Inspector

Incoming Data (from client)
         │
         ▼
  [ Pydantic Inspector ]
    ✓ Is every required field present?
    ✓ Is each value the right type?
    ✓ Does each value pass field rules?
         │
    Pass → clean Python object → your function
    Fail → 422 error with exact problem description

A Basic Pydantic Model

from pydantic import BaseModel

class Order(BaseModel):
    item_name: str
    quantity: int
    price_per_unit: float
    gift_wrap: bool = False

Each line declares a field. The type after the colon is enforced. The = False makes gift_wrap optional with a default value.

Field Validators — Adding Rules Beyond Type

Import Field from Pydantic to add rules like minimum value, maximum length, or a regex pattern:

from pydantic import BaseModel, Field

class Product(BaseModel):
    name: str = Field(min_length=2, max_length=100)
    price: float = Field(gt=0, description="Price must be positive")
    stock: int = Field(ge=0, le=10000)
Field constraint shortcuts:
  gt  = greater than
  ge  = greater than or equal to
  lt  = less than
  le  = less than or equal to
  min_length / max_length  → for strings
  pattern                  → regex match

Email and URL Validation

Pydantic includes special types for common formats. Install the email validator first:

pip install "pydantic[email]"
from pydantic import BaseModel, EmailStr, HttpUrl

class ContactForm(BaseModel):
    email: EmailStr
    website: HttpUrl
Valid:   {"email": "user@example.com", "website": "https://mysite.com"}
Invalid: {"email": "not-an-email", "website": "not-a-url"}
         → 422 error on both fields

Nested Models

Pydantic models can contain other Pydantic models. This mirrors real-world structures like an order that contains an address:

class Address(BaseModel):
    street: str
    city: str
    pincode: str

class Order(BaseModel):
    item: str
    quantity: int
    shipping_address: Address   ← nested model
Valid body:
{
  "item": "Laptop",
  "quantity": 1,
  "shipping_address": {
    "street": "12 MG Road",
    "city": "Bengaluru",
    "pincode": "560001"
  }
}

Pydantic validates both the outer model and every nested model.

Lists Inside Models

from typing import List

class Cart(BaseModel):
    user_id: int
    items: List[str]
    coupon_codes: List[str] = []
{
  "user_id": 7,
  "items": ["Shoes", "Belt", "Watch"],
  "coupon_codes": ["SAVE10"]
}

Custom Validators with @validator

For rules that go beyond field constraints, write a custom validator method:

from pydantic import BaseModel, validator

class Registration(BaseModel):
    username: str
    password: str
    confirm_password: str

    @validator("confirm_password")
    def passwords_must_match(cls, v, values):
        if "password" in values and v != values["password"]:
            raise ValueError("Passwords do not match")
        return v
Bad input:
  password         = "abc123"
  confirm_password = "xyz999"
  → 422: Passwords do not match

Good input:
  password         = "abc123"
  confirm_password = "abc123"
  → Passes validation

Viewing Validation Errors

When Pydantic rejects data, FastAPI returns a 422 response with a structured list of problems:

{
  "detail": [
    {
      "loc": ["body", "price"],
      "msg": "ensure this value is greater than 0",
      "type": "value_error.number.not_gt"
    },
    {
      "loc": ["body", "name"],
      "msg": "ensure this value has at least 2 characters",
      "type": "value_error.any_str.min_length"
    }
  ]
}

Each error shows exactly which field failed and why. Clients can display these messages to end users without any extra work on your part.

Key Points

  • Pydantic enforces types and rules on every field of incoming data.
  • Use Field() to add constraints like gt, min_length, and pattern.
  • Use EmailStr and HttpUrl for format validation on common types.
  • Nested models validate inner objects automatically.
  • Custom @validator methods handle business rules that simple type hints cannot express.

Leave a Comment

Your email address will not be published. Required fields are marked *