@validator runs on a single field — you can transform or validate one field's value.
@root_validator
runs on the entire model's data — useful when validation depends on multiple fields together (like
password confirmation or date range checks). root_validator receives all field values as a dict. Use
pre=True to run before field validation, post (default) to run after.
3.2 Request & Response Schemas
# Separate schemas for Create, Update, Response (best practice)
class UserBase(BaseModel):
name: str
email: str
class UserCreate(UserBase): # for POST — includes password
password: str
class UserUpdate(BaseModel): # for PATCH — all fields optional
name: Optional[str] = None
email: Optional[str] = None
class UserResponse(UserBase): # for GET — excludes password
id: int
created_at: datetime
is_active: bool
class Config:
orm_mode = True
# Using exclude / include
user = UserResponse(...)
[Link](exclude={'created_at'}) # exclude fields
[Link](include={'id', 'name'}) # only these fields
[Link](exclude_none=True) # skip None values
💡 Interview Tip: Always use separate schemas for Create, Update, and Response. Never expose
password hashes or internal fields in response schemas. This shows maturity in API design.
📘 SECTION 4: Dependency Injection
4.1 Depends() — Core Concept
from fastapi import FastAPI, Depends, HTTPException
from [Link] import Session
from typing import Generator
# DB session dependency
def get_db() -> Generator:
db = SessionLocal()
try:
yield db
finally:
[Link]()
# Reusable query params dependency