Express Zod 驗證:打造型別安全且強健的 API 請求校驗

後端開發中有一句至理名言:「永遠不要相信客戶端傳過來的任何資料」。為了確保系統安全、資料一致性並避免因格式錯誤導致的崩潰,我們需要強大的驗證工具。在現代 Node.js 與 TypeScript 生態系中,Zod 是目前公認最優雅、功能最全的選擇。

為什麼選擇 Zod?

  1. 開發者友好:宣告式的 Schema 定義,語法直觀易懂。
  2. 型別推導:能自動從 Schema 生成 TypeScript 型別,減少重複定義。
  3. 功能豐富:支援自定義報錯訊息、資料轉換 (Transform) 與複雜的邏輯校驗 (Refine)。

安裝與基礎用法

npm install zod

定義驗證 Schema

const { z } = require('zod');

const loginSchema = z.object({
  // 鏈式呼叫:必須是字串、符合 Email 格式、帶有自定義錯誤訊息
  email: z.string().email('電子郵件格式不正確'),
  password: z.string().min(8, '密碼長度至少需 8 位'),
});

在 Express 路由中實戰

你可以使用 safeParse 進行不拋出異常的驗證,這在處理邏輯分支時非常方便。

app.post('/api/login', (req, res) => {
  const result = loginSchema.safeParse(req.body);

  if (!result.success) {
    // 驗證失敗,回傳結構化的錯誤資訊
    return res.status(400).json({
      errors: result.error.flatten().fieldErrors,
    });
  }

  // 驗證成功,result.data 是經過校驗且乾淨的資料
  const { email, password } = result.data;
  res.send('驗證通過,準備登入...');
});

進階:封裝驗證中間件 (Middleware)

為了保持路由處理器的整潔,我們建議將驗證邏輯封裝成中間件。

const validate = (schema) => (req, res, next) => {
  try {
    // parse 會在驗證失敗時直接拋出 ZodError
    schema.parse({
      body: req.body,
      query: req.query,
      params: req.params,
    });
    next();
  } catch (err) {
    // 配合先前提過的「集中式錯誤處理器」
    next(err);
  }
};

// 使用時極簡且優雅
app.post('/api/profile', validate(profileSchema), (req, res) => {
  res.send('資料格式完全正確!');
});

Zod 的殺手鐧功能

  • .default():若欄位缺失,自動補上預設值。
  • .transform():在驗證的同時轉換資料(例如將字串轉為數字)。
  • .refine():執行自定義邏輯(例如檢查「密碼」與「確認密碼」是否一致)。
const passwordSchema = z
  .object({
    password: z.string(),
    confirm: z.string(),
  })
  .refine((data) => data.password === data.confirm, {
    message: '兩次輸入的密碼不一致',
    path: ['confirm'],
  });

總結

  1. 安全第一:在資料進入資料庫或核心邏輯前,必須經過 Schema 驗證
  2. 自動化:利用 Middleware 模式,讓驗證變成一道自動閘門。
  3. Zod 不僅是驗證器,更是你定義系統資料模型 (Model) 的基石。