兩個用 Python 寫的 API
版本 A:Django REST Framework
# models.py
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
# serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'name', 'email']
# views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# urls.py
router = DefaultRouter()
router.register(r'users', UserViewSet)這四個檔案,你得到了完整的 CRUD API:GET /users/、POST /users/、GET /users/1/、PUT /users/1/、DELETE /users/1/,全部自動生成,還有 pagination、filter、search 可以加。
版本 B:FastAPI
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
email: str
users_db: list[dict] = []
@app.get("/users")
def get_users():
return users_db
@app.post("/users", status_code=201)
def create_user(user: User):
users_db.append(user.dict())
return user這樣得到 GET /users 和 POST /users,你要自己寫其他的。
兩個版本解決的是一樣的需求,但你能看見的邏輯量完全不同。
Magic 是什麼
Magic 是「框架根據 convention 自動為你做了某些事,但你看不到它在哪裡做的」。
Django ModelViewSet 的 magic:
queryset = User.objects.all()→ 框架自動把它接到GET /endpointserializer_class = UserSerializer→ 框架自動用它來序列化和反序列化- CRUD 的 URL routing 自動從 router.register 生成
- pagination 預設就存在,除非你關掉
這些行為在 Django 的父類裡面。你繼承 ModelViewSet,得到所有行為,但你的程式碼裡看不到這些行為在哪裡被定義。
Magic 的優點:開發速度極快。標準 CRUD 幾乎不用寫邏輯。
Magic 的代價:出了問題,debug 路徑是「去讀父類的原始碼」或「搜 Stack Overflow 那個神奇的行為是怎麼覆寫的」。自訂行為需要知道框架在哪個 hook 點讓你插入。
Explicit 是什麼
Explicit 是「每一個行為都在你的程式碼裡可見,你能追蹤執行路徑」。
Express 的 explicit:
// 你看得到每個 middleware 的掛載順序
app.use(morgan('dev'));
app.use(cors(corsConfig));
app.use(express.json());
// 你看得到每個 route 指向哪個 handler
app.get('/users', authenticate, UserController.index);
app.post('/users', authenticate, validate(userSchema), UserController.store);
// 你看得到 error 是怎麼被接住的
app.use((err, req, res, next) => {
res.status(err.statusCode || 500).json({ error: err.message });
});每一行都是你寫的,每一行都在說「這裡做了什麼」。
Explicit 的優點:出了問題,你直接在你的程式碼裡追蹤執行路徑。沒有隱藏行為,什麼都在你眼前。
Explicit 的代價:每個東西都要自己搭。你要設計 config 管理、要決定 error 處理策略、要選擇 DI 方式——這些在 opinionated 框架裡框架替你決定了。
光譜上的主要框架
Magic ←————————————————————————————————→ Explicit
Rails Django Spring Boot FastAPI NestJS Express Gin
Laravel DRF Laravel Hono Fastify
這不是嚴格的排列,而是大致的位置感。
最 magic 的一端:Rails 和 Laravel。User.find(1) 就是查資料庫,has_many :posts 就是建立 association,你不需要設定任何東西,只要符合 convention。
中間地帶:Spring Boot 和 NestJS。有 DI container 管理依賴,有 decorator / annotation 定義行為,但比 Rails 更 explicit——你看得到 @Injectable() 和 @Controller(),知道 Spring 在管理什麼。
最 explicit 的一端:Express 和 Gin。路由是你宣告的,middleware 是你掛的,error handler 是你寫的,DI 是你自己管的。框架只提供最薄的一層抽象。
什麼情況選哪邊
沒有絕對正確的答案,但有幾個可以幫助判斷的維度:
選 magic-heavy 框架(Rails / Django / Laravel)的情況:
- 需求標準:CRUD 為主,不太需要自訂 HTTP 行為
- 團隊小、需要快速迭代
- 後端不是核心競爭力,只是「讓前端有 API 可以用」
選 explicit 框架(Express / Gin / FastAPI)的情況:
- 需求特殊:streaming、WebSocket、特殊的 auth 流程、複雜的 middleware 邏輯
- 團隊想要完全掌控架構決策
- 需要精確控制效能瓶頸
選中間地帶(NestJS / Spring Boot)的情況:
- 大型系統:需要 DI container 讓依賴管理不失控
- 多人開發:framework 的結構 convention 讓 onboarding 成本降低
- 需要 opinionated 架構但不需要 magic routing
真正的問題不是選哪個
選框架最常見的錯誤是:用你熟悉的語言選,而不是依需求選。
用 Express 做一個大型 ERP 後端,你會花大量時間自己搭 DI、搭生命週期管理、搭統一錯誤處理——這些 NestJS 都已經做好了。
用 Django 做一個需要自訂 streaming response 或複雜 WebSocket 行為的系統,你會花大量時間對抗 Django 的 convention,最後發現 FastAPI 更適合。
問的問題應該是:這個系統的核心需求,和這個框架的設計哲學,吻合程度有多高?
