【Python 後端開發】APIFlask 完整入門指南:更優雅的 RESTful API 框架

前言

前陣子在構思後端重構該用哪個框架的時候,礙於公司內部較習慣使用 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 python

Homebrew 會自動安裝最新版的 Python。

安裝 PDM

這邊我使用 pdm,一個可以同時管理環境和套件的工具,如果還不知道 pdm 是什麼的可以參考:

👉 延伸閱讀: 告別 pip 與 poetry!PDM 讓你的 Python 專案管理更有效率

pip install pdm

pdm init

安裝 APIFlask

pdm add apiflask

非常好,pdm 幫我們裝了一堆有的沒的依賴套件。

python apiflask tutorial 1

這是目前的檔案結構:

├── 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.pysrc/ 資料夾內,我需要在執行前先告訴 Flask 正確的應用程式路徑。

# macOS
export FLASK_APP=src/main.py

# windows
set FLASK_APP=src/main.py  

flask run
python apiflask tutorial 2

打開 http://127.0.0.1:5000/docs# 看看 OpenAPI 文件,看起來就跟一般 Flask 一樣,沒關係~我們先來寫幾隻 API。

python apiflask tutorial 3

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 被清楚的標示出來了:

python apiflask tutorial 5

接下來讓我們把每隻 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

  • redoc
  • elements
  • rapidoc
  • rapipdf
app = APIFlask(__name__, docs_ui="elements")

自訂 API 文件標題和版本

我們還可以自訂這個文件的 title 和 version。

app = APIFlask(__name__, docs_ui="elements", title='Demo API', version='1.0')

重啟 API,可以看到首頁這邊成功顯示我們自訂的名稱和版本!

python apiflask tutorial 4

總結

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

如果想看更多進階的功能,歡迎底下留言告訴我~