目錄
01-2. 環境設定與第一個 API
⏱️ 閱讀時間: 15 分鐘 🎯 難度: ⭐ (入門)
🎯 本章目標
完成這一章後,你將能:
- ✅ 設定 FastAPI 開發環境
- ✅ 建立並運行第一個 API
- ✅ 理解 FastAPI 應用的基本結構
- ✅ 使用 Swagger UI 測試 API
🔧 環境準備
1. 確認 Python 版本
FastAPI 需要 Python 3.8+,建議使用 3.10+
# 檢查 Python 版本
python --version
# 或
python3 --version
# 輸出應該是 Python 3.8 以上
# Python 3.11.x 或 Python 3.12.x2. 建立專案目錄
# 建立專案目錄
mkdir fastapi-learning
cd fastapi-learning
# 建立虛擬環境
python -m venv venv
# 啟動虛擬環境
# macOS / Linux
source venv/bin/activate
# Windows (Command Prompt)
venv\Scripts\activate.bat
# Windows (PowerShell)
venv\Scripts\Activate.ps1確認虛擬環境啟動成功:
# 你的終端機應該顯示 (venv) 前綴
(venv) $ which python
/path/to/fastapi-learning/venv/bin/python3. 安裝 FastAPI
# 安裝 FastAPI(包含所有功能)
pip install "fastapi[standard]"
# 這會安裝:
# - fastapi: 核心框架
# - uvicorn: ASGI 伺服器
# - pydantic: 資料驗證
# - starlette: Web 框架核心
# - httpx: HTTP 客戶端(測試用)
# - jinja2: 模板引擎
# - python-multipart: 表單支援驗證安裝:
# 檢查 FastAPI 版本
python -c "import fastapi; print(fastapi.__version__)"
# 輸出: 0.109.0 或更高
# 檢查 Uvicorn
uvicorn --version
# 輸出: uvicorn 0.27.0 或更高🚀 第一個 FastAPI 應用
建立 main.py
# main.py
from fastapi import FastAPI
# 建立 FastAPI 應用實例
app = FastAPI()
# 定義根路徑
@app.get("/")
async def root():
return {"message": "Hello, FastAPI!"}
# 定義另一個端點
@app.get("/hello/{name}")
async def say_hello(name: str):
return {"message": f"Hello, {name}!"}啟動伺服器
# 開發模式啟動(自動重載)
uvicorn main:app --reload
# 參數說明:
# main: 檔案名稱 (main.py)
# app: FastAPI 實例名稱
# --reload: 程式碼修改時自動重啟成功啟動後會看到:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to stop)
INFO: Started reloader process [28720] using WatchFiles
INFO: Started server process [28722]
INFO: Waiting for application startup.
INFO: Application startup complete.測試 API
打開瀏覽器訪問:
| URL | 說明 |
|---|---|
| http://127.0.0.1:8000 | 根路徑 |
| http://127.0.0.1:8000/hello/John | 帶參數的路徑 |
| http://127.0.0.1:8000/docs | Swagger UI 文件 |
| http://127.0.0.1:8000/redoc | ReDoc 文件 |
📖 程式碼詳解
導入 FastAPI
from fastapi import FastAPI這行導入 FastAPI 類別,它是整個框架的核心。
建立應用實例
app = FastAPI()可以加入更多設定:
app = FastAPI(
title="我的第一個 API",
description="這是一個學習用的 API",
version="0.1.0",
docs_url="/docs", # Swagger UI 路徑
redoc_url="/redoc", # ReDoc 路徑
openapi_url="/openapi.json" # OpenAPI schema
)路由裝飾器
@app.get("/")
async def root():
return {"message": "Hello, FastAPI!"}解析:
| 部分 | 說明 |
|---|---|
@app.get | HTTP GET 方法 |
"/" | URL 路徑 |
async def | 非同步函數(也可用 def) |
root | 函數名稱(會出現在文件中) |
return {...} | 回傳 JSON |
支援的 HTTP 方法
@app.get("/items") # 讀取資源
@app.post("/items") # 建立資源
@app.put("/items/{id}") # 更新資源(完整)
@app.patch("/items/{id}") # 更新資源(部分)
@app.delete("/items/{id}") # 刪除資源
@app.options("/items") # 獲取支援的方法
@app.head("/items") # 獲取 headers(無 body)🎨 Swagger UI 導覽
訪問 http://127.0.0.1:8000/docs:
┌──────────────────────────────────────────────┐
│ 我的第一個 API [Authorize] │
│ 這是一個學習用的 API │
├──────────────────────────────────────────────┤
│ │
│ default │
│ ┌────────────────────────────────────────┐ │
│ │ GET / Root │ │
│ │ 讀取根路徑 │ │
│ └────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────┐ │
│ │ GET /hello/{name} Say Hello │ │
│ │ 向指定名稱打招呼 │ │
│ └────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────┘功能:
- 📋 查看所有 API 端點
- 🧪 線上測試 API
- 📄 查看請求/回應格式
- 🔐 測試認證功能
📝 完整範例:待辦事項 API
讓我們建立一個稍微複雜的範例:
# main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Optional
from datetime import datetime
app = FastAPI(
title="待辦事項 API",
description="一個簡單的待辦事項管理 API",
version="1.0.0"
)
# 資料模型
class TodoCreate(BaseModel):
title: str
description: Optional[str] = None
completed: bool = False
class Todo(BaseModel):
id: int
title: str
description: Optional[str] = None
completed: bool
created_at: datetime
# 模擬資料庫
todos_db: dict[int, Todo] = {}
todo_id_counter = 0
# API 端點
@app.get("/")
async def root():
"""歡迎訊息"""
return {"message": "歡迎使用待辦事項 API!請訪問 /docs 查看文件"}
@app.get("/todos", response_model=list[Todo])
async def get_todos():
"""獲取所有待辦事項"""
return list(todos_db.values())
@app.get("/todos/{todo_id}", response_model=Todo)
async def get_todo(todo_id: int):
"""獲取單一待辦事項"""
if todo_id not in todos_db:
raise HTTPException(status_code=404, detail="待辦事項不存在")
return todos_db[todo_id]
@app.post("/todos", response_model=Todo, status_code=201)
async def create_todo(todo: TodoCreate):
"""建立新的待辦事項"""
global todo_id_counter
todo_id_counter += 1
new_todo = Todo(
id=todo_id_counter,
title=todo.title,
description=todo.description,
completed=todo.completed,
created_at=datetime.now()
)
todos_db[todo_id_counter] = new_todo
return new_todo
@app.put("/todos/{todo_id}", response_model=Todo)
async def update_todo(todo_id: int, todo: TodoCreate):
"""更新待辦事項"""
if todo_id not in todos_db:
raise HTTPException(status_code=404, detail="待辦事項不存在")
existing = todos_db[todo_id]
updated_todo = Todo(
id=todo_id,
title=todo.title,
description=todo.description,
completed=todo.completed,
created_at=existing.created_at
)
todos_db[todo_id] = updated_todo
return updated_todo
@app.delete("/todos/{todo_id}", status_code=204)
async def delete_todo(todo_id: int):
"""刪除待辦事項"""
if todo_id not in todos_db:
raise HTTPException(status_code=404, detail="待辦事項不存在")
del todos_db[todo_id]測試流程
# 1. 啟動伺服器
uvicorn main:app --reload
# 2. 使用 curl 測試(或用 Swagger UI)
# 建立待辦事項
curl -X POST "http://127.0.0.1:8000/todos" \
-H "Content-Type: application/json" \
-d '{"title": "學習 FastAPI", "description": "完成第一章"}'
# 回應:
# {"id":1,"title":"學習 FastAPI","description":"完成第一章","completed":false,"created_at":"2025-12-17T10:30:00"}
# 獲取所有待辦事項
curl "http://127.0.0.1:8000/todos"
# 獲取單一待辦事項
curl "http://127.0.0.1:8000/todos/1"
# 更新待辦事項
curl -X PUT "http://127.0.0.1:8000/todos/1" \
-H "Content-Type: application/json" \
-d '{"title": "學習 FastAPI", "completed": true}'
# 刪除待辦事項
curl -X DELETE "http://127.0.0.1:8000/todos/1"🔄 同步 vs 非同步
FastAPI 同時支援兩種寫法:
非同步函數(推薦)
@app.get("/async")
async def async_endpoint():
# 使用 await 呼叫非同步操作
data = await fetch_data_from_db()
return data適合:
- I/O 操作(資料庫、API 呼叫、檔案讀寫)
- 高併發場景
同步函數
@app.get("/sync")
def sync_endpoint():
# 一般的同步操作
data = compute_something()
return data適合:
- CPU 密集運算
- 使用不支援非同步的函式庫
選擇建議
┌─────────────────────────────────────────────┐
│ 你的操作是什麼類型? │
├─────────────────────────────────────────────┤
│ │
│ I/O 操作(資料庫、HTTP、檔案) │
│ → 使用 async def + await │
│ │
│ CPU 密集運算(計算、處理) │
│ → 使用 def │
│ │
│ 混合(兩者都有) │
│ → 使用 async def,CPU 部分用 run_in_executor │
│ │
└─────────────────────────────────────────────┘⚙️ Uvicorn 進階配置
常用啟動參數
# 基本開發模式
uvicorn main:app --reload
# 指定 host 和 port
uvicorn main:app --host 0.0.0.0 --port 8080
# 指定 workers(生產環境)
uvicorn main:app --workers 4
# 完整配置
uvicorn main:app \
--host 0.0.0.0 \
--port 8000 \
--workers 4 \
--log-level info \
--access-log使用 Python 啟動
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello!"}
# 直接執行此檔案時啟動伺服器
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8000,
reload=True, # 開發模式
log_level="info"
)# 現在可以直接執行
python main.py📁 建議的檔案結構
目前只有一個檔案沒關係,但建議從一開始就養成好習慣:
fastapi-learning/
├── venv/ # 虛擬環境
├── app/
│ ├── __init__.py
│ └── main.py # 主程式
├── requirements.txt # 依賴清單
├── .env # 環境變數
├── .gitignore
└── README.mdrequirements.txt:
fastapi[standard]>=0.109.0.gitignore:
venv/
__pycache__/
*.pyc
.env
.DS_Store✅ 重點總結
環境設定
# 1. 建立虛擬環境
python -m venv venv
source venv/bin/activate # macOS/Linux
# 2. 安裝 FastAPI
pip install "fastapi[standard]"
# 3. 啟動伺服器
uvicorn main:app --reload基本結構
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello!"}重要 URL
| URL | 說明 |
|---|---|
http://127.0.0.1:8000 | API 根路徑 |
http://127.0.0.1:8000/docs | Swagger UI |
http://127.0.0.1:8000/redoc | ReDoc |
🎤 面試這樣答
Q: 如何啟動 FastAPI 應用?
答案:
FastAPI 應用需要 ASGI 伺服器來運行。開發時常用 Uvicorn:
uvicorn main:app --reload生產環境則會用 Gunicorn 配合 Uvicorn workers,或直接用 Uvicorn 配合多個 workers:
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker
🤓 小測驗
FastAPI 需要什麼伺服器來運行?
@app.get("/")中的get代表什麼?Swagger UI 的預設路徑是什麼?
--reload參數的作用是什麼?
🏋️ 練習作業
建立一個簡單的「書籍管理 API」:
GET /books- 獲取所有書籍GET /books/{id}- 獲取單一書籍POST /books- 新增書籍(title, author, year)DELETE /books/{id}- 刪除書籍
上一篇: 01-1. FastAPI 是什麼?為什麼選擇它? 下一篇: 01-3. 路徑參數與查詢參數
最後更新:2025-12-17