前言
前陣子在構思後端重構該用哪個框架的時候,礙於公司內部較習慣使用 Flask,但個人又很希望能有驗證機制(不然前端會把我殺了),不停的 google 終於讓我找到了,就是 APIFlask!
什麼是 APIFlask?
隨著 RESTful API 的開發效率和維護性變得越來越重要。APIFlask 作為一個基於 Flask 的專業 API 開發框架,完美繼承了 Flask 的簡潔設計理念,同時為開發者提供了更強大的 API 開發工具集。
APIFlask 特點
- 請求/響應驗證
APIFlask 的核心設計理念是「簡單」,它保持了 Flask 簡潔直觀的特性,同時提供了豐富的 API 開發特性。參數驗證來自 Marshmallow,Marshmallow 是個透過數據序列化讓我們進行參數驗證的工具,確保 API 的輸入輸出能夠符合格式,讓前後端在溝通上更有效率和直觀。
類似 FastAPI 的 Pydantic 套件,不過兩者底層實現的方式不一樣,詳細可以參考 Medium 這篇。
- 內建跨域資源共享(CORS)
CORS 是一種瀏覽器安全機制,用於控制不同網域之間的資源訪問,它允許伺服器明確指定哪些來源可以訪問其資源,藉此防止未經授權的跨域請求。
APIFlask 提供了內建 CORS 的支援,讓開發者能夠輕鬆處理跨域請求問題。這個特性在現代分布式系統中特別重要,因為前後端分離的架構已經成為主流。
- 支援 OpenAPI
APIFlask 能夠自動根據程式碼生成符合 OpenAPI 標準的 API 文件,大大減少了手動編寫和維護文件的工作,非常適合前後端分離的專案。
- 簡單的路由定義
如果有稍微看一下 APIFlask 的官方文件,就可以這些語法糖:@app.input(),@app.output(),@app.get(),@app.post()
為什麼選擇 APIFlask?
- 簡單,非常之簡單!
- 因為支援 OpenAPI,所以可以自動生成 OpenAPI 文件
- 內建請求/響應驗證(類似 FastAPI 的 Pydantic 驗證套件)
- 支援型別提示(Type Hint)
不過其實最大的原因還是公司內部需求啦 XD,好不廢話了,開始!
環境準備
安裝 Python
我們使用 Homebrew 安裝 python,還沒有安裝 Homebrew 可以看 macOS 開發環境太亂?5 分鐘學會 Homebrew 套件管理 這邊文章安裝。
brew install pythonHomebrew 會自動安裝最新版的 Python。
安裝 PDM
這邊我使用 pdm,一個可以同時管理環境和套件的工具,如果還不知道 pdm 是什麼的可以參考:
👉 延伸閱讀: 告別 pip 與 poetry!PDM 讓你的 Python 專案管理更有效率
pip install pdm
pdm init安裝 APIFlask
pdm add apiflask非常好,pdm 幫我們裝了一堆有的沒的依賴套件。

這是目前的檔案結構:
├── README.md
├── pyproject.toml
├── .pdm-python
├── .gitignore
├── pdm.lock
├── .venv/
├── src/ # 專案主要程式碼
└── tests/ # 測試程式碼
└── __init__.py接下來就可以開始寫 API 了,讓我們在 Terminal 輸入以下指令:
mkdir src # 建立 src 資料夾
touch /src/main.py # 建立檔案啟動 APIFlask
還記得 Flask 的五行程式碼嗎?沒錯,APIFlask 也是!
from apiflask import APIFlask
app = APIFlask(__name__)
@app.get('/')
def index():
return {'message': 'hello world'}由於我的 main.py 在 src/ 資料夾內,我需要在執行前先告訴 Flask 正確的應用程式路徑。
# macOS
export FLASK_APP=src/main.py
# windows
set FLASK_APP=src/main.py
flask run
打開 http://127.0.0.1:5000/docs# 看看 OpenAPI 文件,看起來就跟一般 Flask 一樣,沒關係~我們先來寫幾隻 API。

APIFlask 的 CRUD 路由
簡單的 CRUD 用法非常直觀,相信大家都不陌生。
@app.get('/items/<int:item_id>')
def get_items(item_id):
# query data...
return data
@app.post()
def create_item(data):
# create data...
return "Successfully created."
@app.put('/items/<int:item_id>')
def update_item(item_id, data):
# update data...
return "Successfully updated."
@app.delete('/items/<int:item_id>')
def delete_item(item_id):
# delete data...
return "Successfully deleted."剛剛前面說到,APIFlask 支援驗證,所以我們現在來定義一下需要驗證的資料格式。
參數驗證
和 Marshmallow 一樣,參數驗證是使用 Schema 定義的,使用方法也類似 Pydantic。
from apiflask.fields import Integer, String, Boolean, DateTime
from apiflask.validators import Length, Range
class ItemIn(Schema):
name = String(required=True, validate=Length(1, 100))
description = String(required=False, default="No description")
price = Integer(required=True, validate=Range(min=0))
is_available = Boolean(default=True)
class ItemOut(Schema):
id = Integer()
name = String()
description = String()
price = Integer()
is_available = Boolean()
created_at = DateTime()有一些比較常使用的資料格式可以稍微記一下~
required:設定欄位是否必填default:設定欄位的預設值validate:驗證規則,可以用 Length 限制字串長度;Range 限制數值範圍
接下來是響應路由派上用場的時候!
響應路由
輸入參數驗證 (Input)
@app.input() 用於驗證請求的輸入數據,他有兩個重要參數:
- schema(必填):用於定義資料格式和驗證規則
- location(選填):指定要驗證的數據來源位置,常用的 location 包括:
json:驗證請求體中的 JSON 數據(最常用)form:驗證表單數據query:驗證 URL 查詢參數headers:驗證請求標頭cookies:驗證 Cookie 數據
結合 Schema 使用,我們就可以告訴前端在呼叫這支 API 之前需要傳入哪些參數。
@app.post('/items')
@app.input(ItemIn, location="json") # <--
def create_item(data):
# ...輸出參數驗證 (Output)
同一個道理,Output 用於定義 API 回傳的響應格式和行為,它支援多個參數來控制響應的各個方面,第一個參數同樣是 schema。
- schema
- status_code(選填):定義 HTTP 狀態碼
- description(選填):API 文檔中的描述
基本用法:
@app.post('/items')
@app.output(
ItemOut,
status_code=201,
description="You have successfully created a new item."
)
def create_item(data):
# ...如果需要多個狀態:
@app.post('/items')
@app.output(
ItemOut,
status_code=201,
description="You have successfully created a new item."
)
@app.output(
ErrorOut,
status_code=400,
description="Invalid input data"
)
def create_item(data):
# 根據不同情況返回不同狀態
if success:
return item_data, 201
return {'message': 'Creation failed'}, 400不用重新執行 flash run,回到 API 文件,可以看到我們定義的 Schema 被清楚的標示出來了:

接下來讓我們把每隻 API 都加上參數驗證:
app = APIFlask(__name__)
# test data
items = [
{"id": 1, "name": "Item 1"},
{"id": 2, "name": "Item 2"},
]
@app.get('/items')
@app.output(ItemOut(many=True))
def get_items():
return items
@app.get('/items/<int:item_id>')
@app.output(ItemOut)
def get_item(item_id):
item = next((i for i in items if i["id"] == item_id), None)
if item is None:
return {"error": "Item not found"}, 404
return item
@app.post('/items')
@app.input(ItemIn, location="json")
@app.output(ItemOut, status_code=201)
def create_item(data):
new_id = max(item["id"] for item in items) + 1 if items else 1
new_item = {"id": new_id, "name": data["name"]}
items.append(new_item)
return new_item
@app.put('/items/<int:item_id>')
@app.input(ItemIn, location="json")
@app.output(ItemOut)
def update_item(item_id, data):
item = next((i for i in items if i["id"] == item_id), None)
if item is None:
return {"error": "Item not found"}, 404
item["name"] = data["name"]
return item
@app.delete('/items/<int:item_id>')
def delete_item(item_id):
global items
items = [i for i in items if i["id"] ! = item_id]
return {"message": "Item deleted"}, 200一個基本功能的 CRUD 就完成了!
進階設定
如何更換 APIFlask 主題?
如果覺得主題不好看,APIFlask 也提供一些選項來更換,我自己的話喜歡使用 elements:
redocelementsrapidocrapipdf
app = APIFlask(__name__, docs_ui="elements")自訂 API 文件標題和版本
我們還可以自訂這個文件的 title 和 version。
app = APIFlask(__name__, docs_ui="elements", title='Demo API', version='1.0')重啟 API,可以看到首頁這邊成功顯示我們自訂的名稱和版本!

總結
透過本文,我們了解到如何使用 APIFlask 來加快我們開發 API。透過掌握這些基本功能,我們可以輕鬆實現資料驗證、API 文件生成、錯誤處理等關鍵特性。APIFlask 不僅繼承了 Flask 的簡潔特性,還增強了許多專門針對 API 開發的功能,讓開發過程更加高效和規範。
如果想看更多進階的功能,歡迎底下留言告訴我~



