FastAPI Fundamentals and Pydantic Data Validation

Core Features of FastAPI

FastAPI delivers exceptional performance with development efficiency improvements of 200% to 300%. It reduces human errors by approximately 40%, offers intuitive design, and provides easy learning curves. The framework produces concise, low-repetition code while including built-in interactive API documentation for immediate delivery of development results and standardized API development.

Relationship Between Starlette, Pydantic, and FastAPI

Python's type hints serve as the foundation for these tools. Pydantic leverages Python type annotations to define data validation, serialization, and documentation using JSON Schema. Starlette functions as a lightweight ASGI framework and toolkit, ideal for building high-performance AsyncIO services.

ASGI and WSGI utilize specific packages for deployment scenarios.

Pydentic Fundamentals

Leverage Python's type annotations for data validation and settings management. Pydantic provides runtime type hints and friendly error messages when validation fails, defining how data should be stored in pure Python code and validating it accordingly.

Automatic Data Conversion

from pydantic import BaseModel
from datetime import datetime
from typing import Optional, List


class UserProfile(BaseModel):
    identifier: int  # Required field
    username: str = "DefaultUser"  # Optional with default value
    registration_time: Optional[datetime] = None
    connections: List[int] = []  # List elements must be int or convertible to int


incoming_data = {
    "identifier": "456",
    "registration_time": "2021-06-15 14:30",
    "connections": [4, 5, "6"],  # "6" can be converted via int("6")
}
profile = UserProfile(**incoming_data)
print(profile.model_dump())

The input string in connections converts to the defined integer type, and registration_time transforms into the specified datetime type.

Model Attributes and Methods

print(profile.model_dump())
print(profile.model_dump(mode='json'))
print(profile.model_copy())  # Shallow copy operation
print(UserProfile.model_validate(incoming_data))
print(UserProfile.model_validate_json('{"identifier": "456", "registration_time": "2021-06-15 14:30", "connections": [4, 5, "6"]}'))

file_path = Path('validation_example.json')
file_path.write_text('{"identifier": "456", "registration_time": "2021-06-15 14:30", "connections": [4, 5, "6"]}')
print(UserProfile.model_validate_json(file_path.read_text()))

print(profile.model_json_schema())
print(profile.model_json_schema().get('title', 'schema'))

invalid_data = {"identifier": "error", "registration_time": "2021-06-15 14 30", "connections": [4, 5, 6]}  # Invalid string for id
print(UserProfile.model_construct(**invalid_data))  # Creates model without validation - not recommended for unverified data

print(UserProfile.model_fields.keys())  # Maintains field order when all fields have type annotations

Handling Validation Errors

from pydantic import BaseModel, ValidationError
from datetime import datetime
from typing import Optional, List


class UserProfile(BaseModel):
    identifier: int  # Required field
    username: str = "DefaultUser"  # Optional with default value
    registration_time: Optional[datetime] = None
    connections: List[int] = []  # List elements must be int or convertible to int


try:
    UserProfile(identifier=2, registration_time=datetime.now(), connections=[7, 8, "invalid_number"])
except ValidationError as error:
    print(error.model_dump_json())

Nested Model Structures

from pydantic import BaseModel
from datetime import datetime, date
from typing import Optional, List

class Vocalization(BaseModel):
    audio: str


class Canine(BaseModel):
    birth_date: date
    mass: float = Optional[None]
    vocalizations: List[Vocalization]  # Different dogs have different sounds - nested model structure


dog_collection = Canine(birth_date=date.today(), mass=8.88, vocalizations=[{"audio": "bark bark ~"}, {"audio": "yip yip ~"}])
print(dog_collection.model_dump())

ORM Integration: Creating Models Compatible with ORM Objects

from pydantic import BaseModel
from pydantic import constr
from typing import List
from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import declarative_base


Base = declarative_base()

class OrganizationOrm(Base):
    __tablename__ = 'organizations'
    id = Column(Integer, primary_key=True, nullable=False)
    api_key = Column(String(20), index=True, nullable=False, unique=True)
    company_name = Column(String(63), unique=True)
    website_list = Column(ARRAY(String(255)))


class OrganizationModel(BaseModel):
    id: int
    api_key: constr(max_length=20)
    company_name: constr(max_length=63)
    website_list: List[constr(max_length=255)]

    class Config:
        from_attributes = True


org_orm = OrganizationOrm(
    id=789,
    api_key='testkey',
    company_name='Sample Corp',
    website_list=['site1.com', 'site2.com'],
)

print(OrganizationModel.model_validate(org_orm))

Tags: FastAPI pydantic python web development Data Validation

Posted on Mon, 12 Oct 2026 16:33:40 +0000 by lakshmiyb