您的 API 正在執行。您可以在 http://localhost:8000/docs 看到它在運作。但在 Cursor 生成的那些檔案中究竟發生了什麼事?本章將引導您瀏覽程式碼,讓您了解您正在使用的內容。我們將探索每個檔案,解釋關鍵概念,並向您展示如何使用 Cursor 本身作為學習工具。讀完本章,您將了解您的 API 實際上是如何運作的。
使用 Cursor 來學習程式碼#
在我們深入探討之前,這裡有一個技巧可以讓理解程式碼變得容易得多:要求 Cursor 解釋它。說真的。編寫程式碼的 AI 可以解釋程式碼。方法如下:2.
按 Cmd+K (Mac) 或 Ctrl+K (Windows/Linux)
3.
詢問:"解釋這段程式碼做什麼" 或 "為什麼我們需要這個?"
當我們瀏覽檔案時,請儘管使用這個功能。我會解釋大局,但如果您想要任何特定部分的更多細節,只需詢問 Cursor。
專案結構概覽#
在 Cursor 中打開您的專案。您應該會看到類似這樣的內容:user-api/
├── main.py # 入口點 - 啟動 API
├── database.py # 資料庫設定和連接
├── auth.py # JWT token 函式
├── dependencies.py # 可重複使用的元件
├── models/
│ └── user.py # 資料庫表定義
├── schemas/
│ └── user.py # API 請求/回應格式
├── routers/
│ └── users.py # 您所有的端點
├── requirements.txt # 依賴項
├── .env.example # 環境變數範本
├── README.md # 設定說明
└── users.db # SQLite 資料庫(首次執行後出現)
入口點 (main.py) 建立 API 並連接一切。路由器 (routers/users.py) 處理每個端點的 HTTP 請求。Schemas (schemas/user.py) 定義資料在請求和回應中的樣子。Models (models/user.py) 定義資料在資料庫中的樣子。資料庫 (database.py) 管理與 SQLite 的連接。Auth (auth.py) 處理用於身分驗證的 JWT tokens。依賴項 (dependencies.py) 提供可重複使用的函式,如「獲取當前使用者」。
main.py - 入口點#
該檔案建立了您的 FastAPI 應用程式。就是 app = FastAPI() 那一行。其他一切都是配置。Base.metadata.create_all() 自動建立您的資料庫表。第一次執行 API 時,它會發現您沒有 users 表並建立它。這就是為什麼您不需要執行單獨的資料庫設定指令。CORS middleware 允許您的 API 接收來自網頁瀏覽器的請求。在開發中,它是完全開放的 (allow_origins=["*"])。在生產環境中,您會限制為特定網域。app.include_router(users.router) 連接您所有的使用者端點。沒有這一行,端點將無法訪問。就是這樣。入口點出奇地簡單,因為所有真正的工作都發生在其他檔案中。
database.py - 資料庫連接#
engine 是您的資料庫連接。它知道如何與 SQLite 對話。SessionLocal 建立資料庫工作階段 (sessions)。每次您想與資料庫互動時,您會建立一個工作階段,完成工作,然後關閉它。Base 是您的模型繼承的基礎。還記得 models/user.py 嗎?它使用這個 Base 來成為資料庫表。get_db() 是一個函式,它給您一個資料庫工作階段,並在您完成後自動關閉它。這透過 FastAPI 的依賴注入在整個 API 中使用。對於開發來說,SQLite 很完美。它只是一個檔案 (users.db),無需管理單獨的伺服器。當您部署到生產環境時,您只需更改一行即可使用 PostgreSQL。其餘程式碼保持不變,因為 SQLAlchemy (ORM) 抽象了資料庫差異。
models/user.py - 資料庫表#
這是您的資料庫 schema。 每個 Column 都會成為 users 表中的一列。id 使用 UUID (通用唯一識別碼),看起來像 "a8f3c2e1-4b7d-4e9a-b3c1-8f2d3e4a5b6c"。default=lambda: str(uuid.uuid4()) 會在您建立使用者時自動生成一個新的隨機 ID。email 有 unique=True,這意味著資料庫將拒絕重複的電子郵件。它還有 index=True 以加快查詢速度。nullable=False 表示該欄位是必需的。nullable=True 表示它是可選的。注意這裡有一個 password 欄位。這儲存雜湊後的密碼(不是純文字)。我們將在查看路由器時看到雜湊是如何運作的。不要混淆 models/user.py 和 schemas/user.py:Schemas 定義 API 資料格式(發送/接收什麼)
它們很相似但服務於不同目的。您稍後會明白為什麼我們兩者都需要。
schemas/user.py - API 資料格式#
UserCreate 是客戶端在建立使用者時發送的內容。它包含密碼,因為他們需要設定密碼。它驗證電子郵件實際上是電子郵件格式 (EmailStr)。UserResponse 是 API 返回的內容。注意它不包含密碼。這是一個安全功能。密碼欄位是唯寫的 - 您可以發送它,但永遠拿不回來。UserUpdate 用於更新使用者。所有欄位都是 Optional,因為您可能只想更新 firstName 而不更改其他任何內容。這些 schemas 使用 Pydantic,它會自動驗證資料。如果有人發送 "email": "not-an-email",Pydantic 會在您的程式碼執行之前拒絕它。如果他們發送 "age": 25 但 age 不在您的 schema 中,Pydantic 會忽略它。這就是為什麼 FastAPI 如此強大 - 透過定義這些 schemas,您即可獲得自動驗證和自動文件。
routers/users.py - 您的端點#
這是真正工作發生的地方。打開 routers/users.py,您將看到所有六個端點。POST /users - 建立使用者#
@router.post("/users") 說「此函式處理對 /users 的 POST 請求」response_model=UserResponse 告訴 FastAPI 使用 UserResponse schema 格式化回應(排除密碼)status_code=201 設定成功建立的 HTTP 狀態碼user: UserCreate 意味著 FastAPI 將自動解析請求 body 為 JSON 並根據 UserCreate schema 進行驗證db: Session = Depends(get_db) 是 FastAPI 的依賴注入。它從 database.py 調用 get_db(),給您一個資料庫工作階段。當函式結束時,工作階段自動關閉。6.
重新整理以獲取生成的欄位(如 id, createdAt)
7.
返回使用者(FastAPI 自動將其轉換為 UserResponse 格式)
POST /user/login - 登入#
透過電子郵件尋找使用者。如果未找到,返回 401(不要告訴客戶端是電子郵件存在還 是密碼錯誤 - 這是一個安全慣例)。使用 bcrypt 驗證密碼。它將提交的密碼雜湊,並將其與儲存的雜湊進行比較。如果匹配,密碼正確。如果有效,建立一個包含使用者 ID 的 JWT token(sub 是 "subject" 的標準 JWT 欄位)。返回 token。客戶端將在受保護端點的 Authorization header 中包含此 token。PUT /users/{id} - 更新使用者(受保護)#
current_user: User = Depends(get_current_user) - 此端點需要身分驗證。get_current_user 依賴項從 Authorization header 中提取 JWT token,驗證它,並載入使用者。如果 token 無效或遺失,請求甚至在執行此函式之前就會失敗。if current_user.id != id: - 使用者只能更新自己的帳戶。即使擁有有效 token,您也不能修改其他人的資料。user_update.dict(exclude_unset=True) - 僅更新實際提供的欄位。如果客戶端發送 {"firstName": "NewName"},則只有 firstName 改變。exclude_unset=True 忽略請求中沒有的欄位。
auth.py - JWT Token 處理#
當使用者登入時,create_access_token() 建立一個 JWT token。此 token 是一個包含使用者 ID 和過期時間的加密簽章字串。簽章使用 SECRET_KEY,因此 token 無法偽造。Token 在 24 小時後過期 (ACCESS_TOKEN_EXPIRE_HOURS)。之後,使用者需要再次登入。hash_password() 獲取純密碼如 "SecurePass123" 並將其轉換為類似 "$2b$12$KIXxE.j3vFg9QN8hA6Fv0e..." 的東西。這是一個單向轉換 - 您無法反轉它以獲得原始密碼。verify_password() 獲取純密碼和雜湊,雜湊純密碼,並比較雜湊。如果它們匹配,則密碼正確。這意味著即使您的資料庫被入侵,攻擊者也無法獲得實際密碼。
dependencies.py - 可重複使用的元件#
HTTPBearer() 從請求中提取 Authorization: Bearer <token> header。get_current_user() 是受保護端點使用的依賴項。它:1.
從 Authorization header 獲取 token
如果任何步驟失敗(遺失 token、無效簽章、過期 token、使用 者已刪除),它會引發 401 錯誤。這就是為什麼受保護端點只需使用 Depends(get_current_user) 即可自動訪問經過驗證的使用者。依賴項系統非常優雅。
一切如何組合在一起#
讓我們在系統中追踪一個完整的請求。假設客戶端想要更新他們的名字:PUT /users/abc123
Authorization: Bearer eyJhbGc...
{"firstName": "NewName"}
2. FastAPI 路由(在 main.py 中)看到這與 routers/users.py 中的 PUT /users/{id} 端點匹配get_current_user() 驗證 JWT token 並載入使用者
4. Pydantic 驗證 將請求 body 解析為 UserUpdate schema 並驗證它FastAPI 將 User model 轉換為 UserResponse schema
{
"id": "abc123",
"email": "user@example.com",
"firstName": "NewName",
...
}
所有這些都自動發生。您只需在端點函式中編寫商業邏輯。
關鍵概念總結#
依賴注入:
FastAPI 的 Depends() 自動提供資料庫工作階段、當前使用者等。這保持程式碼乾淨並處理設定/清理。自動驗證:
Pydantic schemas 自動驗證所有輸入。壞資料永遠不會到達您的程式碼。資料庫抽象:
SQLAlchemy ORM 意味著您編寫 Python,而不是 SQL。從 SQLite 切換到 PostgreSQL 只是更改連接字串。
您學到了什麼#
更重要的是,您知道如何使用 Cursor 來探索程式碼。選擇任何您不理解的東西,按 Cmd+K,然後提問。生成此程式碼的 AI 是您的學習夥伴。
下一步是什麼#
在下一章中,您將學習如何自訂和擴充此 API。想新增新欄位?更改某些運作方式?新增全新的功能?我們將向您展示如何使用 Cursor 快速且正確地進行這些更改。首先,讓我們確保一切實際上都運作正常,透過在 Apidog 中正確地測試它。 Modified at 2025-12-29 09:35:19