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))