Skip to main content

Zod

安裝

npm install 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 的 typeinterface,來進行最基本的型別檢查。 如果發生預期外的錯誤,可以直接對定義的型別進行調整, 或者是透過 Logger 來了解錯誤是在哪邊發生的。

參考文章