iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0

今天我們要建立一個完整的 FastAPI 應用程式,作為後續 Locust 測試的目標。這個應用將包含典型的電商使用者行為:註冊、登入、瀏覽商品、購買等功能。

專案結構

day14/
├── README.md
├── app/
│   ├── __init__.py
│   ├── main.py              # FastAPI 應用主程式
│   ├── models.py            # 資料模型
│   ├── database.py          # 資料庫設定
│   └── auth.py             # 認證相關函數
├── requirements.txt         # 依賴套件
└── test_data.py            # 測試資料初始化

功能需求

我們的 FastAPI 應用需要包含以下功能:

  1. 使用者管理

    • 使用者註冊
    • 使用者登入/登出
    • JWT Token 認證
  2. 商品管理

    • 商品列表查詢
    • 商品詳情查詢
  3. 購物功能

    • 添加商品到購物車
    • 查看購物車
    • 結帳購買

實作步驟

1. 安裝依賴套件

# requirements.txt
fastapi==0.104.1
uvicorn==0.24.0
sqlalchemy==2.0.23
python-jose[cryptography]==3.3.0
python-multipart==0.0.6
bcrypt==4.0.1

2. 資料庫模型設計

# app/models.py
from sqlalchemy import Column, Integer, String, Float, Boolean, DateTime, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime

Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True, index=True)
    hashed_password = Column(String)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.utcnow)

class Product(Base):
    __tablename__ = "products"
    
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String, index=True)
    description = Column(String)
    price = Column(Float)
    stock = Column(Integer, default=0)
    is_available = Column(Boolean, default=True)

class CartItem(Base):
    __tablename__ = "cart_items"
    
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    product_id = Column(Integer, ForeignKey("products.id"))
    quantity = Column(Integer, default=1)
    
    user = relationship("User")
    product = relationship("Product")

class Order(Base):
    __tablename__ = "orders"
    
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    total_amount = Column(Float)
    status = Column(String, default="pending")
    created_at = Column(DateTime, default=datetime.utcnow)
    
    user = relationship("User")

3. FastAPI 主應用程式

# app/main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer
from sqlalchemy.orm import Session
from typing import List
import uvicorn

app = FastAPI(title="Shop API", version="1.0.0")

@app.get("/")
def root():
    return {"message": "Welcome to Shop API"}

@app.post("/register")
def register(user_data: dict, db: Session = Depends(get_db)):
    # 註冊邏輯
    return {"message": "User registered successfully"}

@app.post("/login")
def login(credentials: dict, db: Session = Depends(get_db)):
    # 登入邏輯
    return {"access_token": "fake_token", "token_type": "bearer"}

@app.get("/products")
def get_products(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
    # 回傳商品列表
    return [
        {"id": 1, "name": "iPhone 15", "price": 35900, "stock": 50},
        {"id": 2, "name": "MacBook Pro", "price": 65900, "stock": 20},
        {"id": 3, "name": "AirPods", "price": 5490, "stock": 100},
        {"id": 4, "name": "iPad", "price": 15900, "stock": 30}
    ]

@app.get("/products/{product_id}")
def get_product(product_id: int, db: Session = Depends(get_db)):
    # 回傳特定商品
    products = {
        1: {"id": 1, "name": "iPhone 15", "description": "最新款 iPhone", "price": 35900, "stock": 50},
        2: {"id": 2, "name": "MacBook Pro", "description": "M3 晶片筆電", "price": 65900, "stock": 20},
        3: {"id": 3, "name": "AirPods", "description": "無線耳機", "price": 5490, "stock": 100},
        4: {"id": 4, "name": "iPad", "description": "平板電腦", "price": 15900, "stock": 30}
    }
    if product_id not in products:
        raise HTTPException(status_code=404, detail="Product not found")
    return products[product_id]

@app.post("/cart/items")
def add_to_cart(item: dict, db: Session = Depends(get_db)):
    # 添加商品到購物車
    return {"message": "Item added to cart"}

@app.get("/cart")
def get_cart(db: Session = Depends(get_db)):
    # 查看購物車
    return {
        "items": [
            {"product_name": "iPhone 15", "price": 35900, "quantity": 1, "subtotal": 35900}
        ],
        "total_amount": 35900
    }

@app.post("/checkout")
def checkout(db: Session = Depends(get_db)):
    # 結帳
    return {
        "message": "Order completed successfully",
        "order_id": 12345,
        "total_amount": 35900
    }

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

快速啟動

# 1. 安裝依賴
pip install fastapi uvicorn

# 2. 啟動應用
uvicorn app.main:app --reload

# 3. 查看 API 文檔
# 瀏覽器開啟 http://localhost:8000/docs

API 測試範例

# 註冊使用者
curl -X POST "http://localhost:8000/register" \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser","email":"test@example.com","password":"password123"}'

# 登入
curl -X POST "http://localhost:8000/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser","password":"password123"}'

# 查看商品
curl -X GET "http://localhost:8000/products"

# 添加到購物車
curl -X POST "http://localhost:8000/cart/items" \
  -H "Content-Type: application/json" \
  -d '{"product_id":1,"quantity":2}'

# 結帳
curl -X POST "http://localhost:8000/checkout"

總結

今天我們建立了一個簡化版的 FastAPI 電商應用,包含:

  1. 使用者系統:註冊、登入
  2. 商品系統:商品列表、商品詳情
  3. 購物功能:購物車、結帳
  4. API 文檔:自動生成的 Swagger 文檔

這個應用將作為明天 Day15 Locust 測試的目標,我們將模擬多個使用者同時進行各種操作,測試系統的效能表現。


上一篇
Day13 - Locust Custom Clients 自訂客戶端
系列文
Vibe Coding 後的挑戰:Locust x Loki 負載及監控14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言