1. Cài đặt môi trường phát triển
Yêu cầu hệ thống
- Python 3.12+ (khuyến nghị 3.12 hoặc 3.13)
- uv hoặc Poetry cho dependency management
- VS Code hoặc PyCharm với Python extension
- Git cho version control
Cài đặt Python 3.12+
# macOS (Homebrew)
brew install [email protected]
# Ubuntu/Debian
sudo apt update
sudo apt install python3.12 python3.12-venv python3.12-dev
# Windows - tải từ https://python.org
# Kiểm tra version
python3 --version
# Python 3.12.x
Cài đặt uv (Recommended)
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Kiểm tra
uv --version
2. Khởi tạo FastAPI Project
# Tạo project mới
uv init fastapi-tutorial
cd fastapi-tutorial
# Thêm FastAPI và Uvicorn
uv add fastapi "uvicorn[standard]"
# Thêm dev dependencies
uv add --dev ruff mypy pytest httpx
# Xem project structure
tree .
File pyproject.toml sau khi khởi tạo:
[project]
name = "fastapi-tutorial"
version = "0.1.0"
description = "FastAPI Tutorial - From Basic to Advanced"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.32.0",
]
[dependency-groups]
dev = [
"httpx>=0.28.0",
"mypy>=1.13.0",
"pytest>=8.3.0",
"ruff>=0.8.0",
]
[tool.ruff]
target-version = "py312"
line-length = 120
[tool.ruff.lint]
select = ["E", "F", "I", "N", "W", "UP", "B", "A", "SIM", "TCH"]
[tool.mypy]
python_version = "3.12"
strict = true
3. Cấu trúc Project
Tạo cấu trúc thư mục chuẩn:
# Tạo cấu trúc thư mục
mkdir -p app/{api/v1,models,schemas,services,core}
touch app/__init__.py app/main.py app/config.py
touch app/api/__init__.py app/api/v1/__init__.py
touch app/models/__init__.py app/schemas/__init__.py
touch app/services/__init__.py app/core/__init__.py
fastapi-tutorial/
├── pyproject.toml
├── uv.lock
├── .env
├── .gitignore
├── app/
│ ├── __init__.py
│ ├── main.py # Entry point
│ ├── config.py # Configuration
│ ├── api/
│ │ ├── __init__.py
│ │ └── v1/
│ │ ├── __init__.py
│ │ └── items.py # Item routes
│ ├── models/
│ │ └── __init__.py
│ ├── schemas/
│ │ ├── __init__.py
│ │ └── item.py # Pydantic schemas
│ ├── services/
│ │ └── __init__.py
│ └── core/
│ └── __init__.py
└── tests/
└── __init__.py
4. Viết FastAPI Application đầu tiên
app/config.py - Configuration
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "FastAPI Tutorial"
app_version: str = "0.1.0"
debug: bool = True
model_config = {"env_file": ".env", "env_file_encoding": "utf-8"}
settings = Settings()
app/schemas/item.py - Pydantic Schemas
from pydantic import BaseModel, Field
class ItemBase(BaseModel):
name: str = Field(..., min_length=1, max_length=100, examples=["Laptop"])
description: str | None = Field(None, max_length=500, examples=["A powerful laptop"])
price: float = Field(..., gt=0, examples=[999.99])
is_available: bool = Field(True)
class ItemCreate(ItemBase):
pass
class ItemUpdate(BaseModel):
name: str | None = Field(None, min_length=1, max_length=100)
description: str | None = Field(None, max_length=500)
price: float | None = Field(None, gt=0)
is_available: bool | None = None
class ItemResponse(ItemBase):
id: int
model_config = {"from_attributes": True}
app/api/v1/items.py - Route Handlers
from fastapi import APIRouter, HTTPException, status
from app.schemas.item import ItemCreate, ItemResponse, ItemUpdate
router = APIRouter(prefix="/items", tags=["Items"])
# In-memory storage (sẽ thay bằng database sau)
fake_db: dict[int, dict] = {}
counter = 0
@router.get("/", response_model=list[ItemResponse])
async def list_items(skip: int = 0, limit: int = 10):
"""Lấy danh sách items với pagination."""
items = list(fake_db.values())
return items[skip : skip + limit]
@router.get("/{item_id}", response_model=ItemResponse)
async def get_item(item_id: int):
"""Lấy thông tin item theo ID."""
if item_id not in fake_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item with id {item_id} not found",
)
return fake_db[item_id]
@router.post("/", response_model=ItemResponse, status_code=status.HTTP_201_CREATED)
async def create_item(item: ItemCreate):
"""Tạo item mới."""
global counter
counter += 1
item_data = {"id": counter, **item.model_dump()}
fake_db[counter] = item_data
return item_data
@router.put("/{item_id}", response_model=ItemResponse)
async def update_item(item_id: int, item: ItemUpdate):
"""Cập nhật item theo ID."""
if item_id not in fake_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item with id {item_id} not found",
)
stored_item = fake_db[item_id]
update_data = item.model_dump(exclude_unset=True)
stored_item.update(update_data)
fake_db[item_id] = stored_item
return stored_item
@router.delete("/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_item(item_id: int):
"""Xóa item theo ID."""
if item_id not in fake_db:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item with id {item_id} not found",
)
del fake_db[item_id]
app/main.py - Entry Point
from fastapi import FastAPI
from app.api.v1.items import router as items_router
from app.config import settings
app = FastAPI(
title=settings.app_name,
version=settings.app_version,
description="FastAPI Tutorial - Learning from basic to advanced",
docs_url="/docs", # Swagger UI
redoc_url="/redoc", # ReDoc
openapi_url="/openapi.json",
)
# Include routers
app.include_router(items_router, prefix="/api/v1")
@app.get("/")
async def root():
return {
"app": settings.app_name,
"version": settings.app_version,
"docs": "/docs",
}
@app.get("/health")
async def health_check():
return {"status": "healthy"}
5. Chạy Development Server
# Chạy với uv
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# Hoặc chạy trực tiếp
uvicorn app.main:app --reload
# Output:
# INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
# INFO: Started reloader process [12345] using WatchFiles
# INFO: Started server process [12346]
# INFO: Waiting for application startup.
# INFO: Application startup complete.
Uvicorn Options quan trọng
# Development
uvicorn app.main:app \
--reload \ # Auto-reload khi code thay đổi
--host 0.0.0.0 \ # Listen all interfaces
--port 8000 \ # Port
--log-level debug # Log level
# Production (preview)
uvicorn app.main:app \
--workers 4 \ # Số worker processes
--host 0.0.0.0 \
--port 8000 \
--no-access-log # Tắt access log cho performance
6. Khám phá Swagger UI & ReDoc
Sau khi chạy server, truy cập:
- Swagger UI:
http://localhost:8000/docs- Interactive API documentation - ReDoc:
http://localhost:8000/redoc- Alternative documentation - OpenAPI JSON:
http://localhost:8000/openapi.json- Raw OpenAPI spec
Swagger UI cho phép:
- Xem tất cả API endpoints với HTTP methods
- Xem request/response schemas
- "Try it out" - gọi API trực tiếp từ browser
- Xem example values và validation rules
7. Test API với curl
# Health check
curl http://localhost:8000/health
# Tạo item
curl -X POST http://localhost:8000/api/v1/items/ \
-H "Content-Type: application/json" \
-d '{"name": "Laptop", "description": "Gaming laptop", "price": 1299.99}'
# Lấy danh sách items
curl http://localhost:8000/api/v1/items/
# Lấy item theo ID
curl http://localhost:8000/api/v1/items/1
# Cập nhật item
curl -X PUT http://localhost:8000/api/v1/items/1 \
-H "Content-Type: application/json" \
-d '{"price": 999.99}'
# Xóa item
curl -X DELETE http://localhost:8000/api/v1/items/1
8. VS Code Setup cho FastAPI
Cài đặt extensions cần thiết:
// .vscode/extensions.json
{
"recommendations": [
"ms-python.python",
"ms-python.vscode-pylance",
"charliermarsh.ruff",
"ms-python.mypy-type-checker"
]
}
// .vscode/settings.json
{
"python.defaultInterpreterPath": ".venv/bin/python",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
}
}
Tổng kết
Trong bài này, chúng ta đã:
- Cài đặt Python, uv và FastAPI
- Khởi tạo project với cấu trúc thư mục chuẩn
- Viết ứng dụng CRUD API đầu tiên với Pydantic schemas
- Chạy development server và khám phá Swagger UI
- Cấu hình VS Code cho Python development
Bài tiếp theo sẽ đi sâu vào Path Operations, Request và Response handling trong FastAPI.