JSON Schema 到底能解決什麼問題
結論:Schema 管的是結構與型別,管不了業務語意。它能把「欄位缺失、型別錯、枚舉越界」擋在入口,但「金額為負、結束時間早於開始時間」這類規則,得靠程式碼驗證。

結論:JSON Schema 負責結構、型別、取值範圍與格式,跨欄位依賴、業務不變量與外部狀態必須放回程式碼;介面對外開放或多服務共享資料時引入,內部小服務欄位少時手寫判斷更快。
能解決「這份資料長得對不對」,解決不了「這份資料說不說得通」。
它擅長的部分
結構完整性。 該有的欄位有沒有,多餘的欄位允不允許(required、additionalProperties)。
型別正確性。 port 是數字還是字串,tags 是陣列還是單一值。跨語言系統裡這一條能省掉大量型別判斷程式碼。
取值範圍。 枚舉(enum)、數值區間(minimum/maximum)、字串長度、陣列長度。
格式約束。 日期、電子郵件、URI、UUID 這些有公認寫法的欄位,用 format 宣告。
巢狀結構。 物件裡套物件、陣列裡套物件,每一層都能單獨約束,錯誤訊息能精確到路徑。
契約文件化。 Schema 本身就是介面文件,改欄位必須改 Schema,評閱時一眼能看出影響範圍。它還能反向產生 TypeScript 型別、Go 結構體、表單設定,屬於「一處定義、多處消費」。
它管不了的部分
跨欄位依賴。 「結束時間必須晚於開始時間」用 if/then/else 能硬寫,但寫出來又長又難讀,維護成本高於直接在程式碼裡寫三行判斷。
業務不變量。 「庫存不能為負」「同一訂單號不能重複」,這依賴外部狀態,Schema 只看單份資料。
語意正確性。 price: -100 完全符合 {"type": "number"},但它是不是合法的價格,Schema 不知道。
一個實用的分工
| 層次 | 誰負責 |
|---|---|
| 語法:是不是合法 JSON | 解析器 |
| 結構:欄位、型別、範圍、格式 | JSON Schema |
| 語意:跨欄位、業務規則、外部狀態 | 業務程式碼 |
| 安全:體積、深度、頻率 | 閘道 / 中介層 |
四層混在一起做,最常見的後果是 Schema 膨脹到幾百行、if/then 巢狀五六層,改一個欄位要半天,最後大家繞開驗證直接改程式碼。
什麼時候值得引入
- 介面對外開放,呼叫方不可控
- 多個服務消費同一份資料,結構漂移會連鎖出錯
- 設定驅動,需要在校驗階段攔住手寫錯誤
- 需要用 Schema 反向產生型別或表單
如果只是內部小服務、欄位三五個、呼叫方就一個前端,寫 if 判斷比維護 Schema 更快。
常見問題
如何判斷一個專案該不該引入 JSON Schema?
看介面是否對外開放、是否有多個服務消費同一份資料、是否需要反向產生型別或表單。若是內部小服務、欄位三五個、呼叫方只有一個前端,寫 if 判斷比維護 Schema 更快。
為什麼跨欄位規則不該硬寫進 Schema?
「結束時間必須晚於開始時間」這類規則雖然能用 if/then/else 表達,但寫出來又長又難讀,維護成本高於直接在程式碼裡寫三行判斷。
是否可以用 Schema 驗證請求體大小與巢狀深度?
不能。Schema 只看資料結構,不限制體積與深度,這類安全約束要在閘道或中介層處理。