從零開始:使用 FastAPI、MySQL 和 Docker 打造你的第一個電商購物車應用
引言:
哈囉,各位程式碼愛好者!你是否曾經想過要打造一個自己的網路應用程式,卻不知道從何開始?特別是對 Python 有興趣的初學者,常常會被複雜的 Web 框架和部署流程嚇到。別擔心!今天,我們將一起踏上一個有趣的旅程,使用 Python 最潮的 Web 框架 FastAPI,結合強大的 MySQL 數據庫,並透過 Docker 讓部署變得輕而易舉,一步步打造一個簡單卻功能齊全的電商購物車應用。
這個應用不只包含後端 API,還有一個簡單的 HTML 前端頁面,讓你直接看到成果!準備好了嗎?讓我們開始吧!
專案 GitHub 連結:https://github.com/BpsEason/ECommerceFastAPI.git
你會學到什麼?
- FastAPI 基礎: 建立 RESTful API 端點、資料驗證。
- 非同步程式設計: 如何在 Python 中處理高併發請求。
- 數據庫操作: 使用 SQLAlchemy 和 AsyncMy 進行非同步 MySQL 數據庫交互。
- 身份驗證: 實作 JWT (JSON Web Token) 認證機制。
- 容器化部署: 使用 Docker 和 Docker Compose 快速部署整個應用。
- 前端互動: 基礎 HTML/CSS/JavaScript 與後端 API 互動。
- 單元測試: 使用 Pytest 確保 API 的正確性。
專案概覽:
我們的電商購物車應用將包含以下幾個部分:
- 後端 API (FastAPI): 提供商品列表、用戶註冊/登入、購物車管理(新增、更新、刪除、查看)等功能。
- 數據庫 (MySQL): 儲存用戶、商品和購物車資料。
- 前端 (HTML/CSS/JS): 簡單的商品展示頁和購物車頁面,透過 JavaScript 與後端 API 互動。
- 容器化 (Docker): 將所有服務打包成獨立的容器,方便部署和管理。
第一步:環境準備 (Docker 是你的好幫手!)
在開始寫程式之前,我們需要準備好開發環境。最簡單的方法就是使用 Docker。
-
安裝 Docker 和 Docker Compose:
- 請訪問
,下載並安裝適用於你作業系統的 Docker Desktop。安裝完成後,Docker Compose 也會一併安裝。Docker 官網
- 請訪問
-
克隆專案程式碼:
- 我們會從 GitHub 下載這個專案的原始碼。打開你的終端機 (Terminal) 或命令提示字元 (Command Prompt),輸入:
Bash
git clone https://github.com/BpsEason/ECommerceFastAPI.git cd ECommerceFastAPI
- 小提示: 如果你沒有安裝 Git,也可以直接從 GitHub 頁面下載 ZIP 壓縮檔並解壓縮。
- 我們會從 GitHub 下載這個專案的原始碼。打開你的終端機 (Terminal) 或命令提示字元 (Command Prompt),輸入:
-
設定 JWT 密鑰:
- JWT (JSON Web Token) 是一種用於身份驗證的開放標準。我們需要一個安全的密鑰來加密和解密它。在專案根目錄下,創建一個名為
.env
的檔案,並在其中添加一行(請將your-secure-jwt-secret-key
替換為你自己的隨機字串,你可以使用openssl rand -hex 32
來生成一個): 例如:JWT_SECRET=你自己的安全密鑰,越長越複雜越好!
JWT_SECRET=f3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
- JWT (JSON Web Token) 是一種用於身份驗證的開放標準。我們需要一個安全的密鑰來加密和解密它。在專案根目錄下,創建一個名為
第二步:啟動你的應用程式 (Docker Compose 一鍵搞定!)
現在,神奇的時刻來了!有了 Docker Compose,你只需要一個命令,就能啟動所有服務:
docker-compose up --build
docker-compose up
:啟動docker-compose.yaml
中定義的所有服務。--build
:如果服務的Dockerfile
或其依賴有更新,會重新構建 Docker 映像。
第一次運行時,Docker 會下載所需的映像檔並構建你的應用程式,這可能需要一些時間。請耐心等待,直到看到類似 api_1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
的訊息,這表示你的後端 API 已經啟動。
重要提示:數據庫初始化!
我們的 FastAPI 應用程式在啟動時,會自動幫你在 ecommerce 數據庫中創建 products、users 和 cart_items 這幾個表格。所以你通常不需要手動創建表格。
如果你想為應用程式添加一些初始商品數據,可以這樣做:
- 打開另一個終端機視窗,進入專案目錄。
- 連接到 MySQL 數據庫容器:
Bash
docker-compose exec db mysql -u root -prootpassword
- 在 MySQL 命令列中,執行以下 SQL 語句插入一些商品:
SQL
USE ecommerce; INSERT INTO products (name, price, stock) VALUES ('Python 初學者入門套件', 199.99, 100), ('FastAPI 實戰指南', 29.50, 50), ('Docker 精通之路', 45.00, 75);
第三步:探索你的應用程式
現在,你的電商應用已經在運行了!
-
前端介面: 打開你的網頁瀏覽器,訪問
http://localhost:8080
。你應該會看到一個簡單的商品列表頁面。你可以嘗試註冊新用戶、登入,然後將商品加入購物車並查看。 -
API 文件 (Swagger UI): 訪問
http://localhost:8000/docs
。你會看到由 FastAPI 自動生成的互動式 API 文件。你可以在這裡測試所有的 API 端點,包括註冊、登入、查看商品、購物車操作等。
第四步:程式碼導覽 (為初學者設計)
讓我們簡單看看專案中幾個重要的檔案,了解它們是如何協同工作的。
1. main.py
(後端 API)
這是我們 FastAPI 後端的核心程式碼。
# ... (省略部分導入和設定)
# 數據庫模型 - 就像數據庫中的表格藍圖
class Product(Base):
__tablename__ = "products"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), index=True)
price = Column(Float)
stock = Column(Integer)
# Pydantic 模型 - 用於定義 API 請求和回應的資料格式
class UserCreate(BaseModel):
username: str
password: str
# 註冊用戶 API 端點
@app.post("/register", summary="Register a new user")
async def register(user: UserCreate, db: AsyncSession = Depends(get_db)):
# 這裡處理用戶註冊邏輯,包括密碼加密和存入數據庫
# ...
return {"message": "User created successfully"}
# 獲取所有商品 API 端點
@app.get("/products", response_model=List[ProductResponse], summary="Get all products")
async def get_products(db: AsyncSession = Depends(get_db)):
# 從數據庫查詢所有商品
# ...
return result.scalars().all()
# ... (其他 API 端點,如 /token, /cart, PATCH /cart/{item_id}, DELETE /cart/{item_id})
FastAPI
: 輕量級、高效能的 Python Web 框架,用於構建 API。SQLAlchemy
: Python 的 ORM (Object Relational Mapper),讓我們可以用 Python 物件的方式來操作數據庫,而不是直接寫 SQL 語句。asyncmy
: SQLAlchemy 的異步 MySQL 驅動。Pydantic
: 用於資料驗證和設定管理。它確保 API 接收到的資料符合預期格式,並自動生成 API 文件。JWT
和passlib
: 用於實現安全的用戶身份驗證 (JWT) 和密碼加密 (bcrypt)。async
和await
: Python 的異步程式設計語法,讓程式在等待數據庫響應時可以同時處理其他請求,大大提高了應用程式的併發處理能力。@app.post
,@app.get
等裝飾器: FastAPI 用它們來定義不同的 HTTP 方法和路徑。Depends(get_db)
/Depends(get_current_user)
: 這是 FastAPI 的「依賴注入」機制。它會自動處理數據庫連接和用戶認證,讓你的 API 函數保持簡潔。
2. requirements.txt
這個檔案列出了我們的 Python 專案所需的所有第三方庫及其版本。當 Docker 構建 API 服務時,會根據這個檔案來安裝依賴。
fastapi>=0.110.0
uvicorn>=0.28.0
sqlalchemy==2.0.23
asyncmy==0.2.9
python-jose==3.3.0
passlib[bcrypt]==1.7.4
pytest==7.4.0
pytest-asyncio==0.23.0
httpx==0.23.0
slowapi==0.1.9
3. docker-compose.yaml
這是 Docker Compose 的配置文件,它定義了我們應用程式的所有服務 (API、數據庫、前端) 以及它們之間的關係。
version: '3.8'
services:
api: # 後端 FastAPI 服務
build: . # 從當前目錄的 Dockerfile 構建
ports:
- "8000:8000" # 將容器的 8000 端口映射到主機的 8000 端口
depends_on:
- db # 依賴於 db 服務先啟動
env_file:
- ./.env # 從 .env 檔案加載環境變數 (例如 JWT_SECRET)
volumes:
- .:/app # 將當前目錄掛載到容器的 /app 目錄,方便程式碼修改後即時生效
db: # MySQL 數據庫服務
image: mysql:8.0 # 使用 MySQL 8.0 官方映像
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: ecommerce
MYSQL_USER: user
MYSQL_PASSWORD: password
volumes:
- db-data:/var/lib/mysql # 持久化數據,避免容器刪除後數據丟失
frontend: # 前端 Nginx 服務
build: ./frontend # 從 frontend 目錄的 Dockerfile 構建
ports:
- "8080:80" # 將容器的 80 端口 (Nginx 默認端口) 映射到主機的 8080 端口
depends_on:
- api # 依賴於 api 服務先啟動
volumes:
db-data: # 定義一個用於數據庫持久化的命名 Volume
services
: 定義了三個獨立的服務:api
(你的 FastAPI 應用)、db
(MySQL 數據庫) 和frontend
(Nginx 靜態檔案伺服器)。build
: 告訴 Docker Compose 如何構建該服務的 Docker 映像。.
表示在當前服務的上下文中查找Dockerfile
。ports
: 將容器內部的端口映射到你的主機端口,這樣你就可以通過主機訪問這些服務。depends_on
: 指定服務的啟動順序。例如,api
服務會在db
服務啟動後才啟動。environment
: 為容器設置環境變數。volumes
: 用於數據持久化。db-data:/var/lib/mysql
會將 MySQL 數據存儲在 Docker 管理的db-data
Volume 中,這樣即使容器被刪除,數據也不會丟失。.:/app
將主機上的專案程式碼同步到容器中,方便開發時的即時更新。
4. index.html
和 cart.html
(前端介面)
這些是我們簡單的靜態 HTML 頁面,它們使用 JavaScript 來與後端 API 互動。
fetch()
API: JavaScript 的fetch()
函數用於向後端發送 HTTP 請求(例如,獲取商品列表、將商品添加到購物車、登入等)。localStorage
: 用於在瀏覽器中存儲用戶的 JWT token,以便在後續請求中進行身份驗證。
<!-- end list -->
<script>
let token = localStorage.getItem('jwt_token'); // 從本地存儲獲取 token
// 獲取商品列表的函數
async function fetchProducts() {
const response = await fetch('http://localhost:8000/products'); // 向後端 API 發送請求
const products = await response.json();
// ... (將商品顯示在頁面上)
}
// 將商品添加到購物車的函數
async function addToCart(productId) {
if (!token) {
alert('請先登入'); // 如果沒有 token,提示用戶登入
// ...
return;
}
const quantity = document.getElementById(`quantity-${productId}`).value;
const response = await fetch('http://localhost:8000/cart', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // 在請求頭中發送 token
},
body: JSON.stringify({ product_id: productId, quantity: parseInt(quantity) })
});
// ... (處理回應,例如彈出提示)
}
// ... (登入、註冊、登出等函數)
</script>
5. test_api.py
(測試程式碼)
這是一個使用 pytest
框架編寫的測試檔案,用於自動化測試我們的 API 端點是否按預期工作。
import pytest
from fastapi.testclient import TestClient
from main import app, get_db, Base, Product, User, CartItem # 導入必要的模組和模型
# ... (數據庫設置和覆寫依賴)
@pytest.fixture(autouse=True)
async def setup_database():
# 在每次測試前後,清理並重新創建數據庫表格,確保測試隔離
async with main.engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
yield
async with main.engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
@pytest.mark.asyncio
async def test_register_user():
response = client.post("/register", json={"username": "testuser", "password": "testpassword"})
assert response.status_code == 200
assert response.json() == {"message": "User created successfully"}
@pytest.mark.asyncio
async def test_login_success():
# ... (測試登入成功)
pass
# ... (其他測試函數,例如測試獲取商品、添加購物車、更新購物車、刪除購物車)
pytest
: 強大的 Python 測試框架。fastapi.testclient.TestClient
: 允許你在不啟動實際伺服器的情況下,直接對 FastAPI 應用進行測試。@pytest.mark.asyncio
: 讓pytest
能夠運行異步的測試函數。- Fixture (夾具):
setup_database
是一個 fixture,它在每個測試函數運行前後執行代碼(這裡是用於數據庫的設置和清理),確保測試環境的純淨。
第五步:運行測試 (確保一切正常!)
在專案目錄下,執行以下命令來運行你的 API 測試:
docker-compose exec api pytest tests/test_api.py -v
docker-compose exec api
:在正在運行的api
服務容器內部執行命令。pytest tests/test_api.py -v
:運行tests/test_api.py
檔案中的所有測試,-v
參數會顯示詳細的測試結果。
如果一切設置正確,你應該會看到所有測試都通過了!
第六步:一些進階思考 (給未來的你!)
- 錯誤處理優化: 目前前端直接
alert()
錯誤訊息。在實際專案中,你可以設計更友好的錯誤提示 UI,例如在頁面上方顯示一個警告條。 - 前端路由: 對於更複雜的單頁應用程式 (SPA),你可以考慮使用 React、Vue 或 Angular 等前端框架,搭配前端路由來管理頁面跳轉,而不是直接使用多個 HTML 檔案。
- 環境變數管理: 目前
JWT_SECRET
已在.env
中管理。對於前端 API URL 等,也可以考慮通過環境變數或構建工具來動態配置,使其在不同部署環境下更靈活。 - 數據庫遷移: 隨著專案的發展,數據庫結構可能會改變。學習使用數據庫遷移工具 (如
Alembic
配合 SQLAlchemy) 將是管理數據庫變化的好方法。 - 部署到雲端: 當你準備好將應用上線時,可以探索將 Docker 容器部署到雲平台 (如 AWS ECS, Google Cloud Run, Azure Container Instances) 的方法。
結語:
恭喜你!你已經成功地使用 FastAPI、MySQL 和 Docker 構建並運行了一個基本的電商購物車應用。這不僅讓你接觸到了現代 Web 開發的核心技術,也為你未來的學習打下了堅實的基礎。
這只是一個開始,程式設計的世界充滿了無限可能。繼續探索,享受程式碼帶來的樂趣吧!如果你有任何問題或想法,歡迎在下方留言交流!
沒有留言:
張貼留言