在開發後端 API 的時候,你一定遇過這些狀況:
boolean
,結果卻收到 "true"
或 1
。如果每次都要手動檢查 req.body
,程式碼會變得又長又難維護。
👉 這時候,Zod 就是我們的防呆神器。
Zod 是一個 TypeScript-first 的資料驗證工具,它的特點包括:
z.string().min(1)
就能定義規則。先來看一個小範例:
import { z } from "zod";
// 定義 schema
const userSchema = z.object({
name: z.string().min(1, "Name is required"),
age: z.number().int().min(0),
});
// 驗證資料
const result = userSchema.safeParse({ name: "", age: -1 });
if (!result.success) {
console.log(result.error.errors);
// [
// { message: "Name is required", path: ["name"] },
// { message: "Number must be greater than or equal to 0", path: ["age"] }
// ]
}
常見型別:
z.string()
:字串z.number()
:數字z.boolean()
:布林z.object({...})
:物件常用驗證方法:
.min(n)
/ .max(n)
:限制範圍.optional()
:欄位可選.email()
:檢查 Email 格式也可用線上 Zod Playground 快速測試一下:
在專案根目錄執行:
npm install zod
建立 src/validator/todoValidation.ts
:
import { z } from "zod";
export const createTodoSchema = z.object({
title: z
.string()
.min(1, { message: "Title is required" })
.max(100, { message: "Title must be at most 100 characters" }),
});
export const updateTodoSchema = z.object({
title: z.string().optional(),
completed: z.boolean().optional(),
});
在 todoController.ts
中對 createTodo
、updateTodo
套用 .safeParse()
:
import { Request, Response, NextFunction } from "express";
import { AppDataSource } from "../config/db";
import { Todo } from "../entities/Todo";
import { createTodoSchema, updateTodoSchema } from "../validator/todoValidation";
const todoRepository = AppDataSource.getRepository(Todo);
export async function createTodo(req: Request, res: Response, next: NextFunction) {
try {
const parsed = createTodoSchema.safeParse(req.body);
if (!parsed.success) {
res.status(400).json({ status: "failed", message: "標題過長或過短" });
return;
}
const newTodo = todoRepository.create({ title: parsed.data.title });
const savedTodo = await todoRepository.save(newTodo);
res.status(201).json({ status: "success", data: savedTodo });
} catch (error) {
next(error);
}
}
export async function updateTodo(req: Request, res: Response, next: NextFunction) {
try {
const { id } = req.params;
const parsed = updateTodoSchema.safeParse(req.body);
if (!parsed.success) {
res.status(400).json({ status: "failed", message: "更新資料格式錯誤" });
return;
}
const todo = await todoRepository.findOneBy({ id });
if (!todo) {
res.status(404).json({ status: "error", message: "Todo not found" });
return;
}
todo.title = parsed.data.title ?? todo.title;
todo.completed = parsed.data.completed ?? todo.completed;
const updatedTodo = await todoRepository.save(todo);
res.json({ status: "success", data: updatedTodo });
} catch (error) {
next(error);
}
}
✅ 正確資料 → 正常新增 / 更新
❌ 錯誤資料 → 直接被擋下並回傳錯誤訊息
今天我們學到:
safeParse()
可以有效攔截不合法資料。下次寫 API 時,別忘了這個小幫手!
commit : add zod validation