Zod
安裝
- npm
- yarn
- pnpm
npm install zod
yarn add zod
pnpm add zod
基本介紹
前、後端傳遞資料的方式通常都是透過 API 來完成的,
然而雖然有 TypeScript 在幫我們進行型別檢查,
但是在從 API 獲取所需資料時則是在 Runtime 的過程,
因此就需要額外使用 is
關鍵字撰寫驗證函式,
最後在對資料進行驗證。
所以,這時候就可以使用 Zod、yup、io-ts 等函式庫, 來替我們處理資料驗證的部分。
定義 Schema
假設我們今天要建立一個簡易的登入登出功能, 所需要的資料為 User,包含了 username、password、gender 等等的屬性。
首先,可以使用 z.object()
來產生物件 Schema。
import { z } from 'zod';
// 使用 z.object 產生 object schema
export const userSchema = z.object({
id: z.string(),
username: z.string(),
password: z.string().min(8).max(20), // 長度最少為 8,最長為 20
gender: z.string(),
email: z.string().optional(), // 可選的
});
// 也可以透過 z.array 來產生 array schema
export const usersSchema = z.array(userSchema);
在以往的 TypeScript 可能需要去撰寫 type、interface, 但在 Zod 有提供透過 Schema 推斷型別的方法。
export type User = z.TypeOf<typeof userSchema>;
驗證資料
接下來,會分為前端、後端來進行簡易的實作、說明。
前端
以往在撰寫 fetch 函式時,通常都會像下方那樣:
async function fetchUsers(): Promise<User[]> {
const res = await fetch('/api/v1/users');
const data = await res.json();
return data as User[];
}
一旦,後端所提供的資料為空、或者是缺少某些屬性,就會發生預期外的錯誤。
如果是透過 Zod 對資料進行驗證,就能預先對上方的錯誤處理。
async function fetchUsers(): Promise<User[]> {
const res = await fetch('/api/v1/users');
const data = await res.json();
const parsedData = usersSchema.safeParse(data);
if (parsed.success) {
return parsed.data;
}
console.error(parsed.error);
return [];
}
只要使用 safeParse
方法就能夠驗證後端所傳來的資料,同時也不需要再額外進行型別轉換。
後端
而在後端的部分,通常在撰寫 handler 會像以下方式:
export default async function handler(req: Request, res: Response) {
if (req.method === 'POST') {
const { username, password, gender, ...rest } = req.body;
// 逐一進行資料驗證、處理
if (username && password) {
if (password.length > 8) {
// ...
}
}
// 將資料儲存至 database
const id = createUser({ username, password, gender, ...rest });
return res.status(200).json({ message: 'success', user_id: id });
}
}
但透過 Zod 來進行驗證的話,就可以輕鬆的達到同樣效果。
// 使用 omit 方法來去除 id 屬性
const userCreateSchema = userSchema.omit({ id: true });
export default async function handler(req: Request, res: Response) {
if (req.method === 'POST') {
const body = userCreateSchema.parse(req.body);
const id = createUser(body);
return res.status(200).json({ message: 'success', user_id: id });
}
}
parse
方法會在驗證失敗時拋出 Error,
可以透過 try...catch...
或者是 Server 端自定義的錯誤處理函式,
對 Error 進行下一步的處理 (回傳 Response...)。
結語
並不是一定需要透過 Zod 來對資料進行驗證,有時候使用這類的驗證庫反而會更抽象難以理解
,因此如果前端、後端間具有良好的溝通下,
也可以使用 TypeScript 的 type
、interface
,來進行最基本的型別檢查。
如果發生預期外的錯誤,可以直接對定義的型別進行調整,
或者是透過 Logger 來了解錯誤是在哪邊發生的。