~/blog/wordpress-json-schema-validation-design-guide.md
API 串接與系統整合 · 2026 / 01 / 15

API 總是噴錯?用 JSON Schema 打造 WordPress 堅不可摧的資料驗證層

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
API 總是噴錯?用 JSON Schema 打造 WordPress 堅不可摧的資料驗證層
目錄 table-of-contents.md

前端送來的 JSON 少了欄位、該傳數字的地方塞了字串,API 就直接噴錯給你看——資料驗證寫得零散,整個後端就跟著千瘡百孔。與其在每支 API 裡手刻一堆 if 檢查,不如用 JSON Schema 把驗證規則宣告成一份契約。這篇就教你在 WordPress 裡打造堅不可摧的資料驗證層。

你一定遇過這種狀況:前端送來的 JSON 少了欄位,或者是明明該傳數字的地方傳了字串(還是 "null" 這種字串,眼神死),結果你的 PHP 程式碼直接噴出 500 Internal Server Error,然後客戶氣沖沖地跑來問為什麼網站掛了。

在 WordPress 開發 REST API 時,很多工程師習慣用一堆 if ( !isset($_POST['email']) ) 或者 empty() 來檢查。說實話,這種寫法不僅醜,而且維護起來簡直是地獄。如果你的資料結構有三層巢狀迴圈,你的 if-else 大概會縮排到螢幕外面去。

今天這篇文章,我要帶大家進入 JSON Schema 的世界。這不只是為了驗證,更是為了「設計」出結構嚴謹、自我描述的 API。我們會講到如何在 WordPress 中優雅地實作它,拒絕髒資料進入你的資料庫。

什麼是 JSON Schema?為什麼你需要它?

簡單來說,JSON Schema 就是 JSON 資料的「藍圖」或「契約」。它本身也是一段 JSON,用來描述:「我的資料應該長什麼樣子」。

在工程團隊協作(特別是前後端分離)時,JSON Schema 有幾個巨大的好處:

  • 自動化驗證:你不需要手寫幾十行檢查程式碼,只需要定義好規則,驗證器(Validator)會幫你搞定。
  • 即時文件化:Schema 本身就是最好的文件。Swagger (OpenAPI) 基本上就是基於 JSON Schema 產生的。
  • 前後端解耦:後端先把 Schema 開出來,前端依照 Schema 產生假資料(Mock Data)開發,大家不用互相等。
  • 強型別思維:雖然 PHP 是弱型別,但透過 Schema,我們可以強制要求 API 介面的型別嚴謹度。

WordPress REST API 中的 Schema 設計

WordPress 核心的 REST API 其實已經內建了對 Schema 的支援,但很多開發者都忽略了 register_rest_route 中的 schema 參數,只專注在 callback 上。這是非常可惜的。

一個好的 API 設計,應該是「Schema First」。我們先定義資料結構,再寫邏輯。

基礎範例:定義一個產品提交的 Endpoint

假設我們要開一支 API 讓外部系統寫入產品資料,我們希望資料結構包含:產品名稱(字串)、價格(數字)、庫存(整數)、以及標籤(字串陣列)。

如果是傳統寫法,你可能在 callback 裡寫滿了檢查邏輯。但在 JSON Schema 思維下,我們這樣做:

add_action( 'rest_api_init', function () {
    register_rest_route( 'roamer/v1', '/products', array(
        'methods'  => 'POST',
        'callback' => 'roamer_create_product',
        'permission_callback' => function() { return current_user_can('edit_posts'); },
        'args'     => array(), // 這裡我們通常留空,改用 schema 定義
        'schema'   => 'roamer_product_schema',
    ) );
} );

function roamer_product_schema() {
    return array(
        '$schema'              => 'http://json-schema.org/draft-04/schema#',
        'title'                => 'product',
        'type'                 => 'object',
        'properties'           => array(
            'name' => array(
                'description'  => '產品名稱',
                'type'         => 'string',
                'minLength'    => 3,
                'maxLength'    => 100,
            ),
            'price' => array(
                'description'  => '產品價格',
                'type'         => 'number',
                'minimum'      => 0,
            ),
            'stock_qty' => array(
                'description'  => '庫存數量',
                'type'         => 'integer',
                'minimum'      => 0,
            ),
            'tags' => array(
                'description'  => '產品標籤',
                'type'         => 'array',
                'items'        => array(
                    'type' => 'string',
                ),
                'uniqueItems'  => true,
            ),
            'attributes' => array(
                'description' => '巢狀屬性測試',
                'type'        => 'object',
                'properties'  => array(
                    'color' => array( 'type' => 'string' ),
                    'size'  => array( 'type' => 'string', 'enum' => array('S', 'M', 'L') ),
                ),
                'required'    => array('size'),
            ),
        ),
        'required'             => array( 'name', 'price' ),
        'additionalProperties' => false, // 不允許定義以外的垃圾欄位
    );
}

真正的挑戰:如何執行驗證?

這是一個坑。WordPress 的 register_rest_route 雖然讓你定義 schema,但它預設不會自動幫你依照這個 schema 進行嚴格驗證(除非你是使用 REST Controller 模式並繼承 WP_REST_Controller,它會有部分整合)。

如果你只是寫 Closure (匿名函式) 作為 callback,你需要手動觸發驗證。身為工程師,我們當然要自動化這個過程。我們可以使用 rest_validate_request_arg 這個 filter,或者更直接地,在處理請求前先跑一次 Schema Validator。

雖然 WordPress 內建了 rest_validate_value_from_schema 函式,但它對複雜 Schema(如 oneOf, anyOf)的支援度有限。在浪花科技的專案中,如果是複雜的企業級 API,我通常會引入強大的第三方庫,例如 opis/json-schema (支援 Draft 2020-12) 或 justinrainbow/json-schema

使用 WordPress 原生函式進行驗證的實戰

如果不想裝 Composer 套件,我們可以寫一個簡單的中介層(Middleware)或是 Helper Function 來達成基本的 Schema 驗證:

function roamer_validate_request( $request ) {
    $schema = roamer_product_schema();
    $params = $request->get_json_params();

    // 這是 WordPress 內建的驗證器
    $is_valid = rest_validate_value_from_schema( $params, $schema, 'params' );

    if ( is_wp_error( $is_valid ) ) {
        return $is_valid;
    }

    // 額外處理 required (WP 內建函式有時對頂層 required 判斷較寬鬆)
    if ( isset( $schema['required'] ) ) {
        foreach ( $schema['required'] as $field ) {
            if ( ! isset( $params[ $field ] ) ) {
                return new WP_Error( 'rest_missing_callback_param', "缺少必要參數: $field", array( 'status' => 400 ) );
            }
        }
    }

    return true;
}

然後在你的 API Callback 最前面呼叫它:

function roamer_create_product( WP_REST_Request $request ) {
    $validation = roamer_validate_request( $request );
    if ( is_wp_error( $validation ) ) {
        return $validation;
    }

    // 資料是乾淨的,開始寫入資料庫...
    $params = $request->get_json_params();
    // ...
}

進階技巧:巢狀結構與複雜邏輯

JSON Schema 的強大之處在於處理「巢狀結構」。例如上面的 attributes 欄位,我們定義了 size 必須是 'S', 'M', 'L' 其中之一(Enum)。如果前端傳來 'XL',驗證器會直接擋掉。

這在處理 WooCommerce 訂單結構、或是複雜的 CRM 資料同步時非常有用。你不希望寫這種 Code:

if ( isset($data['attributes']) && isset($data['attributes']['size']) && in_array($data['attributes']['size'], ['S','M','L']) ) ...

這簡直是災難。用 Schema,這一切都變得宣告式(Declarative),一目了然。

Eric 的工程師小囉嗦:不要過度設計

雖然 JSON Schema 很棒,但也要提醒大家:不要為了 Schema 而 Schema。如果你只是一個接收「聯絡我們」表單的簡單 API,只有兩個欄位,或許直接用 WordPress 的 validate_callback 就夠了。引入完整的 Schema 驗證流程會有一定的效能開銷(雖然微乎其微)。

但如果你的系統涉及金流、會員資料同步、或者是 SaaS 應用的核心資料交換,請務必把 JSON Schema 加上去。這能讓你的後端像個堡壘一樣,把所有髒東西都擋在護城河外面。

總結

使用 JSON Schema 來設計與驗證 WordPress REST API,能為你帶來以下優勢:

  • 安全性提升:嚴格過濾輸入資料,防止 Injection 或異常資料導致的錯誤。
  • 文件自動化:Schema 就是活的文件。
  • 開發效率:減少手寫重複的驗證邏輯(Boilerplate code)。
  • 維護性:資料結構一目了然,新進工程師也能快速看懂 API 規範。

把資料驗證做好了,你晚上睡覺都會比較安穩,不用擔心半夜被叫起來修 Bug。

延伸閱讀

你的 API 架構需要健檢嗎?
如果你正在為企業開發複雜的 WordPress 系統,或者遇到資料驗證與 API 串接的瓶頸,歡迎找浪花科技聊聊。我們擅長處理高併發、高安全性的系統架構。
立即聯繫我們

// FAQ

常見問題

什麼是 JSON Schema?為什麼 API 開發需要它?
JSON Schema 是描述 JSON 資料結構的「藍圖」或「契約」,本身也是一段 JSON,用來定義資料應有的型別、欄位與規則。它能達成自動化驗證、即時文件化(OpenAPI/Swagger 即基於它)、前後端解耦開發,並為弱型別的 PHP 帶來強型別思維,避免髒資料進入資料庫。
WordPress REST API 定義了 schema 參數會自動驗證資料嗎?
不會自動嚴格驗證。register_rest_route 雖然允許定義 schema,但若 callback 只是匿名函式,WordPress 預設不會依該 schema 進行嚴格驗證(繼承 WP_REST_Controller 的 REST Controller 模式才有部分整合)。因此需要手動觸發驗證,例如在處理請求前先跑一次 Schema Validator。
在 WordPress 中不裝套件要如何驗證 JSON Schema?
可使用 WordPress 內建的 rest_validate_value_from_schema 函式對傳入參數做基本驗證,並在 API callback 最前面呼叫驗證函式、遇到 WP_Error 就提前回傳。由於內建函式對頂層 required 的判斷較寬鬆,建議再自行補一段檢查必填欄位的邏輯。
WordPress 內建的 Schema 驗證對複雜結構夠用嗎?
對複雜 Schema(如 oneOf、anyOf)支援有限。若是複雜的企業級 API,建議引入第三方函式庫,例如支援 Draft 2020-12 的 opis/json-schema,或 justinrainbow/json-schema,以獲得更完整的驗證能力。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?