Học FastAPI: Bắt Đầu Nhanh

FastAPI đã nhanh chóng trở thành một trong những web framework Python phổ biến nhất, và có lý do chính đáng cho điều đó. Nó kết hợp sự dễ dàng của Flask với sức mạnh của các tính năng Python hiện đại, tài liệu API tự động và hiệu suất đáng kinh ngạc. Nếu bạn đang xây dựng API bằng Python, FastAPI nên ở đầu danh sách của bạn.
FastAPI Là Gì?
FastAPI là một web framework hiện đại, hiệu suất cao để xây dựng API với Python 3.8+ dựa trên type hints chuẩn của Python. Được tạo ra bởi Sebastián Ramírez vào năm 2018, nó đã nhanh chóng thu hút sự chú ý nhờ trải nghiệm developer và hiệu suất.
Tính Năng Chính:
- Nhanh - Một trong những Python framework nhanh nhất có sẵn, ngang với NodeJS và Go
- Type hints - Xây dựng trên type hints của Python để hỗ trợ IDE tốt hơn và validation
- Tài liệu tự động - Tài liệu API tương tác được tạo tự động
- Python hiện đại - Sử dụng async/await cho code async hiệu suất cao
- Dựa trên chuẩn - Xây dựng trên OpenAPI và JSON Schema
Tại Sao Chọn FastAPI?
1. Trải Nghiệm Developer Đáng Kinh Ngạc
FastAPI cung cấp autocomplete và validation tuyệt vời ngay lập tức:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
email: str
age: int
@app.post("/users/")
async def create_user(user: User):
# Validation và parsing tự động!
# IDE của bạn biết chính xác các kiểu dữ liệu
return {"message": f"Created user {user.name}"}Lợi Ích:
- Hỗ trợ autocomplete đầy đủ trong IDE
- Validation request tự động
- Thông báo lỗi rõ ràng
- Không cần parsing thủ công
2. Tài Liệu Tương Tác Tự Động
Ngay khi bạn chạy ứng dụng, bạn có tài liệu API đẹp, tương tác tại /docs:
# Chỉ cần chạy ứng dụng
# Truy cập http://localhost:8000/docs
# Xem Swagger UI với tất cả endpoints
# Test API ngay trong trình duyệt!Bạn cũng có tài liệu ReDoc tại /redoc - hai style tài liệu miễn phí!
3. Hiệu Suất Quan Trọng
FastAPI được xây dựng trên Starlette và Pydantic, làm cho nó trở thành một trong những Python framework nhanh nhất:
# Hỗ trợ async cho concurrency cao
@app.get("/items/{item_id}")
async def read_item(item_id: int):
# Xử lý hàng nghìn concurrent requests
result = await fetch_from_database(item_id)
return resultSo sánh hiệu suất:
- FastAPI: ~60,000 requests/giây
- Flask: ~3,000 requests/giây
- Django: ~2,000 requests/giây
Bắt Đầu: Cài Đặt
Thiết lập FastAPI rất đơn giản:
# Tạo virtual environment
python -m venv venv
source venv/bin/activate # Trên Windows: venv\Scripts\activate
# Cài đặt FastAPI và Uvicorn (ASGI server)
pip install "fastapi[standard]"
# Hoặc cài đặt riêng
pip install fastapi uvicorn[standard]Ứng Dụng FastAPI Đầu Tiên
Tạo file main.py:
from fastapi import FastAPI
# Tạo FastAPI instance
app = FastAPI()
# Định nghĩa endpoint đầu tiên
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
return {"item_id": item_id, "q": q}Chạy ứng dụng:
# Start development server
uvicorn main:app --reload
# API của bạn đang chạy tại http://localhost:8000
# Tài liệu có sẵn tại http://localhost:8000/docsĐó là tất cả! Bạn có một API hoạt động với validation tự động, tài liệu và type safety.
Path Parameters và Validation
FastAPI làm cho path parameters type-safe và được validate:
from fastapi import FastAPI, Path
from typing import Annotated
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(
item_id: Annotated[int, Path(title="ID của item", ge=1, le=1000)]
):
return {"item_id": item_id}Điều gì xảy ra ở đây:
item_idphải là integer- Phải nằm giữa 1 và 1000 (ge = greater or equal, le = less or equal)
- Validation và thông báo lỗi tự động
- Được tài liệu hóa trong docs tương tác
Query Parameters
Query parameters hoạt động cũng elegantly:
from fastapi import FastAPI, Query
from typing import Annotated
app = FastAPI()
@app.get("/items/")
async def read_items(
skip: int = 0,
limit: Annotated[int, Query(le=100)] = 10,
search: str | None = None
):
return {
"skip": skip,
"limit": limit,
"search": search
}
# Ví dụ: /items/?skip=20&limit=50&search=pythonRequest Body với Pydantic Models
Pydantic models cung cấp data validation mạnh mẽ:
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime
app = FastAPI()
class User(BaseModel):
username: str = Field(..., min_length=3, max_length=50)
email: EmailStr # Validates email format
full_name: str | None = None
age: int = Field(..., ge=0, le=150)
created_at: datetime = Field(default_factory=datetime.now)
@app.post("/users/")
async def create_user(user: User):
return {
"message": "User created successfully",
"user": user
}Thử request không hợp lệ này:
{
"username": "ab",
"email": "not-an-email",
"age": 200
}Bạn sẽ nhận được lỗi validation chi tiết tự động!
Response Models
Kiểm soát chính xác những gì API của bạn trả về:
from pydantic import BaseModel
class UserIn(BaseModel):
username: str
password: str
email: str
class UserOut(BaseModel):
username: str
email: str
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserIn):
# Password sẽ không có trong response!
return userDependency Injection
FastAPI có hệ thống dependency injection mạnh mẽ:
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
security = HTTPBearer()
async def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)):
if credentials.credentials != "secret-token":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials"
)
return credentials.credentials
@app.get("/protected/")
async def protected_route(token: str = Depends(verify_token)):
return {"message": "You have access!", "token": token}Ví Dụ Tích Hợp Database
Đây là một ví dụ thực tế với SQLAlchemy:
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
# Database setup
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
# Model
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
name = Column(String)
Base.metadata.create_all(bind=engine)
# Dependency
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# FastAPI app
app = FastAPI()
# Pydantic models
from pydantic import BaseModel
class UserCreate(BaseModel):
email: str
name: str
class UserResponse(BaseModel):
id: int
email: str
name: str
class Config:
from_attributes = True
@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate, db: Session = Depends(get_db)):
db_user = User(email=user.email, name=user.name)
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
@app.get("/users/{user_id}", response_model=UserResponse)
def read_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return userBackground Tasks
FastAPI làm cho background tasks trở nên đơn giản:
from fastapi import BackgroundTasks
def send_email(email: str, message: str):
# Giả lập gửi email
print(f"Sending email to {email}: {message}")
@app.post("/send-notification/")
async def send_notification(
email: str,
background_tasks: BackgroundTasks
):
background_tasks.add_task(send_email, email, "Welcome to our service!")
return {"message": "Notification will be sent in background"}Xử Lý Lỗi
Custom exception handlers cho bạn toàn quyền kiểm soát:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
class CustomException(Exception):
def __init__(self, name: str):
self.name = name
app = FastAPI()
@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
return JSONResponse(
status_code=418,
content={"message": f"Oops! {exc.name} did something wrong."}
)
@app.get("/custom/{name}")
async def read_custom(name: str):
if name == "error":
raise CustomException(name=name)
return {"name": name}Testing API Của Bạn
FastAPI apps dễ dàng test với TestClient:
from fastapi.testclient import TestClient
client = TestClient(app)
def test_read_root():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello World"}
def test_create_user():
response = client.post(
"/users/",
json={
"username": "testuser",
"email": "[email protected]",
"age": 25
}
)
assert response.status_code == 200
data = response.json()
assert data["user"]["username"] == "testuser"Best Practices
1. Cấu Trúc Dự Án
myapi/
├── main.py # Entry point
├── api/
│ ├── __init__.py
│ ├── users.py # User routes
│ └── items.py # Item routes
├── models/
│ ├── __init__.py
│ ├── user.py # Database models
│ └── item.py
├── schemas/
│ ├── __init__.py
│ ├── user.py # Pydantic schemas
│ └── item.py
├── services/
│ ├── __init__.py
│ └── user_service.py # Business logic
└── tests/
├── __init__.py
└── test_users.py2. Sử Dụng APIRouter Cho Tính Modular
# api/users.py
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
async def list_users():
return []
# main.py
from api import users
app = FastAPI()
app.include_router(users.router)3. Environment Variables
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
secret_key: str
api_key: str
class Config:
env_file = ".env"
settings = Settings()4. Thêm CORS Middleware
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Các Lỗi Phổ Biến Cần Tránh
1. Trộn Lẫn Sync và Async
# ❌ Không tốt - trộn sync và async
@app.get("/users/")
async def get_users():
users = blocking_database_call() # Chặn event loop!
return users
# ✅ Tốt - giữ nhất quán
@app.get("/users/")
def get_users():
users = blocking_database_call()
return users
# ✅ Tốt hơn - sử dụng async đúng cách
@app.get("/users/")
async def get_users():
users = await async_database_call()
return users2. Không Sử Dụng Response Models
# ❌ Không tốt - không kiểm soát response
@app.get("/users/{user_id}")
def get_user(user_id: int):
user = get_user_from_db(user_id)
return user # Có thể bao gồm password!
# ✅ Tốt - response model rõ ràng
@app.get("/users/{user_id}", response_model=UserOut)
def get_user(user_id: int):
user = get_user_from_db(user_id)
return user # Password tự động được loại bỏKhi Nào Sử Dụng FastAPI vs. Các Framework Khác
Sử dụng FastAPI khi:
- Xây dựng REST APIs hiện đại
- Cần validation và documentation tự động
- Muốn hiệu suất cao với async support
- Xây dựng microservices
- Type safety quan trọng
Cân nhắc các lựa chọn khác:
- Flask: Dự án đơn giản hơn, ecosystem trưởng thành hơn
- Django: Ứng dụng web đầy đủ tính năng với admin panel
- Sanic: Tập trung hoàn toàn vào hiệu suất, ít tính năng hơn
Ví Dụ Thực Tế: Todo API
Đây là một ví dụ hoàn chỉnh, sẵn sàng cho production:
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from typing import List
from datetime import datetime
import uuid
app = FastAPI(title="Todo API", version="1.0.0")
# In-memory storage (sử dụng database thật trong production!)
todos = {}
class TodoCreate(BaseModel):
title: str
description: str | None = None
class TodoUpdate(BaseModel):
title: str | None = None
description: str | None = None
completed: bool | None = None
class Todo(BaseModel):
id: str
title: str
description: str | None
completed: bool
created_at: datetime
updated_at: datetime
@app.post("/todos/", response_model=Todo, status_code=201)
def create_todo(todo: TodoCreate):
todo_id = str(uuid.uuid4())
now = datetime.now()
new_todo = Todo(
id=todo_id,
title=todo.title,
description=todo.description,
completed=False,
created_at=now,
updated_at=now
)
todos[todo_id] = new_todo
return new_todo
@app.get("/todos/", response_model=List[Todo])
def list_todos(skip: int = 0, limit: int = 10):
return list(todos.values())[skip:skip + limit]
@app.get("/todos/{todo_id}", response_model=Todo)
def get_todo(todo_id: str):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
return todos[todo_id]
@app.patch("/todos/{todo_id}", response_model=Todo)
def update_todo(todo_id: str, todo_update: TodoUpdate):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
stored_todo = todos[todo_id]
update_data = todo_update.model_dump(exclude_unset=True)
updated_todo = stored_todo.model_copy(update=update_data)
updated_todo.updated_at = datetime.now()
todos[todo_id] = updated_todo
return updated_todo
@app.delete("/todos/{todo_id}", status_code=204)
def delete_todo(todo_id: str):
if todo_id not in todos:
raise HTTPException(status_code=404, detail="Todo not found")
del todos[todo_id]Các Bước Tiếp Theo
Bây giờ bạn đã hiểu những điều cơ bản, đây là những gì cần khám phá tiếp theo:
-
Authentication & Security
- OAuth2 với JWT tokens
- API key authentication
- Rate limiting
-
Tích Hợp Database
- SQLAlchemy ORM
- Tortoise ORM (async)
- MongoDB với Motor
-
Tính Năng Nâng Cao
- Hỗ trợ WebSocket
- GraphQL với Strawberry
- Upload và download files
- Custom middleware
-
Deployment
- Docker containerization
- Deploy lên AWS/GCP/Azure
- CI/CD pipelines
- Load balancing và scaling
-
Testing & Quality
- Unit testing với pytest
- Integration testing
- Load testing với Locust
- Code coverage
Kết Luận
FastAPI là một bước ngoặt cho phát triển API Python. Nó kết hợp những điều tốt nhất của các tính năng Python hiện đại với trải nghiệm developer xuất sắc, tài liệu tự động và hiệu suất ấn tượng. Cho dù bạn đang xây dựng REST API đơn giản hay kiến trúc microservices phức tạp, FastAPI có các công cụ bạn cần.
Việc framework sử dụng type hints và Pydantic models có nghĩa là ít bug hơn, hỗ trợ IDE tốt hơn và code dễ maintain hơn. Kết hợp với tài liệu tương tác tự động, không có gì ngạc nhiên khi FastAPI đã trở thành một trong những Python frameworks phát triển nhanh nhất.
Bắt đầu xây dựng ứng dụng FastAPI đầu tiên của bạn ngay hôm nay - bạn sẽ ngạc nhiên về việc bạn có thể tạo APIs sẵn sàng cho production nhanh như thế nào với code sạch, type-safe.
Tham Khảo
- Tài Liệu Chính Thức: https://fastapi.tiangolo.com/
- GitHub Repository: https://github.com/tiangolo/fastapi
- Tutorial: https://fastapi.tiangolo.com/tutorial/
- Awesome FastAPI: https://github.com/mjhea0/awesome-fastapi
- Community Discord: Tham gia Discord FastAPI để được giúp đỡ và thảo luận
Chúc bạn code vui vẻ! 🚀
📬 Đăng ký nhận bản tin
Nhận những bài viết mới nhất qua email mỗi tuần. Không spam, hủy đăng ký bất cứ lúc nào.
Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất cứ lúc nào.
💬 Comments
Đăng nhập để bình luận
Chúng tôi sẽ không đăng bất cứ điều gì mà không có sự cho phép của bạn.