Building RESTful APIs with Python
API(Application Programming Interface)是程式之間溝通的介面。
API 就像餐廳的服務生:
你(前端)點餐 → 服務生(API)傳達 → 廚房(後端)做菜 → 服務生送餐回來
REST 是最常見的 API 設計風格,用 HTTP 方法 + URL 表達操作:
| 操作 | HTTP 方法 | URL 範例 | 說明 |
|---|---|---|---|
| 查詢全部 | GET | /api/students | 取得所有學生 |
| 查詢單筆 | GET | /api/students/1 | 取得 ID=1 的學生 |
| 新增 | POST | /api/students | 新增一位學生 |
| 更新 | PUT | /api/students/1 | 更新 ID=1 的學生 |
| 刪除 | DELETE | /api/students/1 | 刪除 ID=1 的學生 |
Create(新增)、Read(讀取)、Update(更新)、Delete(刪除)是 API 最基本的四種操作。
Flask 是 Python 最經典的 Web 框架,語法簡單、適合入門:
pip install flask
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
if __name__ == "__main__":
app.run(debug=True)
儲存為 app.py,執行 python app.py,然後用瀏覽器打開 http://127.0.0.1:5000 就能看到結果。
用 @app.route() 裝飾器定義不同的 URL 路徑和 HTTP 方法:
from flask import Flask, request, jsonify
app = Flask(__name__)
# GET — 首頁
@app.route("/")
def index():
return "歡迎來到我的 API!"
# GET — 帶路徑參數
@app.route("/hello/<name>")
def hello(name):
return f"你好,{name}!"
# POST — 接收 JSON 資料
@app.route("/echo", methods=["POST"])
def echo():
data = request.get_json()
return jsonify({"received": data})
request.get_json() 取得請求的 JSON 資料,jsonify() 回傳 JSON 格式回應。
建立一個學生管理 API,先定義資料結構和查詢功能:
from flask import Flask, request, jsonify
app = Flask(__name__)
# 用 list 模擬資料庫
students = [
{"id": 1, "name": "Ian", "score": 90},
{"id": 2, "name": "Amy", "score": 85},
]
next_id = 3
# GET /api/students — 取得所有學生
@app.route("/api/students")
def get_students():
return jsonify(students)
# GET /api/students/<id> — 取得單一學生
@app.route("/api/students/<int:student_id>")
def get_student(student_id):
student = next((s for s in students if s["id"] == student_id), None)
if student is None:
return jsonify({"error": "找不到學生"}), 404
return jsonify(student)
↓ 往下看新增與更新
新增(POST)與更新(PUT):
# POST /api/students — 新增學生
@app.route("/api/students", methods=["POST"])
def create_student():
global next_id
data = request.get_json()
# 驗證必要欄位
if not data or "name" not in data:
return jsonify({"error": "缺少 name 欄位"}), 400
student = {
"id": next_id,
"name": data["name"],
"score": data.get("score", 0) # 預設 0 分
}
students.append(student)
next_id += 1
return jsonify(student), 201 # 201 = Created
# PUT /api/students/<id> — 更新學生
@app.route("/api/students/<int:student_id>", methods=["PUT"])
def update_student(student_id):
student = next((s for s in students if s["id"] == student_id), None)
if student is None:
return jsonify({"error": "找不到學生"}), 404
data = request.get_json()
student["name"] = data.get("name", student["name"])
student["score"] = data.get("score", student["score"])
return jsonify(student)
↓ 往下看刪除與啟動
刪除(DELETE)與啟動伺服器:
# DELETE /api/students/<id> — 刪除學生
@app.route("/api/students/<int:student_id>", methods=["DELETE"])
def delete_student(student_id):
global students
student = next((s for s in students if s["id"] == student_id), None)
if student is None:
return jsonify({"error": "找不到學生"}), 404
students = [s for s in students if s["id"] != student_id]
return jsonify({"message": f"已刪除學生 {student['name']}"})
# 啟動伺服器
if __name__ == "__main__":
app.run(debug=True, port=5000)
這裡用 list 模擬資料庫,伺服器重啟後資料會消失。實際專案要搭配第十二章學的資料庫。
在終端機中使用 curl 指令測試各個 API:
# 查詢所有學生
curl http://127.0.0.1:5000/api/students
# 查詢單一學生
curl http://127.0.0.1:5000/api/students/1
# 新增學生
curl -X POST http://127.0.0.1:5000/api/students \
-H "Content-Type: application/json" \
-d '{"name": "Tom", "score": 88}'
# 更新學生
curl -X PUT http://127.0.0.1:5000/api/students/1 \
-H "Content-Type: application/json" \
-d '{"score": 95}'
# 刪除學生
curl -X DELETE http://127.0.0.1:5000/api/students/1
也可以用 Postman 或 VS Code 的 REST Client 擴充套件,提供圖形介面更方便。
FastAPI 是 Python 目前最熱門的 API 框架,速度快、自動產生文件:
pip install fastapi uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello, World!"}
@app.get("/hello/{name}")
def hello(name: str):
return {"message": f"你好,{name}!"}
啟動方式:
uvicorn app:app --reload
啟動後打開 http://127.0.0.1:8000/docs 就能看到自動產生的互動式 API 文件(Swagger UI),可以直接在網頁上測試!
同樣的學生管理 API,用 FastAPI 寫法更簡潔:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
# 定義資料模型(自動驗證欄位)
class StudentCreate(BaseModel):
name: str
score: int = 0
class Student(BaseModel):
id: int
name: str
score: int
students = [
{"id": 1, "name": "Ian", "score": 90},
{"id": 2, "name": "Amy", "score": 85},
]
next_id = 3
@app.get("/api/students", response_model=list[Student])
def get_students():
return students
@app.get("/api/students/{student_id}", response_model=Student)
def get_student(student_id: int):
student = next((s for s in students if s["id"] == student_id), None)
if not student:
raise HTTPException(status_code=404, detail="找不到學生")
return student
↓ 往下看新增、更新、刪除
@app.post("/api/students", response_model=Student, status_code=201)
def create_student(data: StudentCreate):
global next_id
student = {"id": next_id, "name": data.name, "score": data.score}
students.append(student)
next_id += 1
return student
@app.put("/api/students/{student_id}", response_model=Student)
def update_student(student_id: int, data: StudentCreate):
student = next((s for s in students if s["id"] == student_id), None)
if not student:
raise HTTPException(status_code=404, detail="找不到學生")
student["name"] = data.name
student["score"] = data.score
return student
@app.delete("/api/students/{student_id}")
def delete_student(student_id: int):
global students
student = next((s for s in students if s["id"] == student_id), None)
if not student:
raise HTTPException(status_code=404, detail="找不到學生")
students = [s for s in students if s["id"] != student_id]
return {"message": f"已刪除學生 {student['name']}"}
FastAPI 用 BaseModel 定義資料模型,如果前端傳的欄位格式不對,會自動回傳 422 錯誤,不需要手動驗證。
| Flask | FastAPI | |
|---|---|---|
| 難度 | 簡單易懂 | 需懂 type hints |
| 效能 | 普通(同步) | 極快(支援非同步) |
| 資料驗證 | 需手動或裝擴充 | Pydantic 自動驗證 |
| API 文件 | 需額外設定 | 自動產生 Swagger UI |
| 生態系 | 歷史悠久、套件最多 | 快速成長中 |
| 適合場景 | 小型專案、學習用 | 正式 API、生產環境 |
初學者先用 Flask 理解 API 基本概念,之後進階到 FastAPI 開發正式專案。
/api/students (O)/api/getStudents (X)/api/students (O)/api/student (X)/api/course-records# 錯誤回應範例
{
"error": "找不到學生",
"status": 404
}
當 API 變複雜時,建議用以下結構組織程式碼:
my_api/
├── app.py # 主程式入口
├── requirements.txt # 套件清單
├── models/ # 資料模型
│ └── student.py
├── routes/ # 路由(各功能的 API)
│ ├── __init__.py
│ └── students.py
├── services/ # 商業邏輯
│ └── student_service.py
└── tests/ # 測試
└── test_students.py
把路由、模型、邏輯分開,每個檔案各司其職,程式碼更好維護和測試。
建立一個待辦事項(Todo)API,支援以下功能:
| 方法 | 路徑 | 功能 |
|---|---|---|
GET | /api/todos | 取得所有待辦事項 |
POST | /api/todos | 新增待辦事項 |
PUT | /api/todos/<id> | 標記為完成 / 更新內容 |
DELETE | /api/todos/<id> | 刪除待辦事項 |
每個 Todo 包含:
{"id": 1, "title": "寫 Python 作業", "done": false}
參考前面的學生管理 API,把 students 改成 todos,欄位改成 title 和 done 即可!
學會了用 Flask 和 FastAPI 建立 RESTful API。