Astro 使用 Zod 驗證網址 Query String 格式
網址中的 Query String 參數驗證是一個還滿常見的需求,通常都會在需要做搜尋或過濾器的頁面中使用,傳統的作法都會是使用 if 判斷式來驗證參數是否符合預期的格式,但這樣的寫法我是覺得還滿醜的說。後來我就嘗試使用 zod 來解析驗證查詢參數,程式碼的確是看起來更簡潔也更好維護了~ 雖然需要稍微了解一下 zod 的用法,但其實也不難上手。
安裝套件
安裝 zod 和 query-string 這兩個套件,因為要解析網址 Query String,因此也一併安裝了 query-string:
npm install zod query-string# oryarn add zod query-string解析 Query String 參數
這邊先看一個解析 Query String 參數的範例:
import { z } from 'zod'import qs from 'query-string'
const defaultParams = { page: 1, priceFrom: 0, priceTo: 1000, sort: 'latest' as 'latest' | 'oldest',}const PRICE_MIN = 0const PRICE_MAX = 1000
const querySchema = z.object({ page: z.coerce.number().positive().default(1).catch(1), type: z.enum(['a', 'b', 'c']).nullish().default(null).catch(null), search: z.coerce.string().nullish().default(null).catch(null), category: z.coerce.number().nullish().default(null).catch(null), priceFrom: z.coerce.number().min(PRICE_MIN).max(PRICE_MAX).default(defaultParams.priceFrom).catch(defaultParams.priceFrom), priceTo: z.coerce.number().min(PRICE_MIN).max(PRICE_MAX).default(defaultParams.priceTo).catch(defaultParams.priceTo), tags: z.preprocess(val => [val || []].flat().map(Number).filter(Boolean), z.array(z.number())).catch([]), sort: z.enum(['latest', 'oldest']).default(defaultParams.sort).catch(defaultParams.sort),})
const params = querySchema.parse(qs.parse(Astro.url.search))以下是 zod 常見驗證查詢參數的範例:
// string 類型z.coerce.string().nullish().default(null).catch(null)
// enum 類型// 預設值為 nullz.enum(['product', 'service']).nullish().default(null).catch(null)// 預設值不為 nullz.enum(['latest', 'oldest']).default('latest').catch('latest')
// number 類型// 預設值為 nullz.coerce.number().nullish().default(null).catch(null)// 預設值不為 nullz.coerce.number().default(0).catch(0)// 限制範圍z.coerce.number().min(0).max(100).default(1).catch(1)
// page 分頁頁數z.coerce.number().positive().default(1).catch(1)
// array 類型// 例如 tags 是 number[] 類型//// array 類型比較複雜,可以先使用 preprocess() 來處理輸入的值,// 將輸入的值轉換成內部都是 Number 的陣列,並且過濾掉非數字的值,// 最後再使用 z.array(z.number()) 來驗證陣列中的值都是數字。z.preprocess(val => [val || []].flat().map(Number).filter(Boolean), z.array(z.number())).catch([])這邊說明一下上面範例中使用到的 zod 方法:
coerce:將值強制轉換為指定的類型。enum:限制值必須是列舉中的其中一個。min:限制值必須大於等於指定的最小值。max:限制值必須小於等於指定的最大值。positive:限制值必須大於 0。default:設定預設值。nullish:允許值為 null 或 undefined。catch:當值無法通過驗證時,使用預設值。preprocess:對值進行預處理。
使用 zod 來驗證查詢參數的關鍵是 coerce、default 和 catch 這三個方法:
coerce用來將值轉換為指定的類型,比如解析數字時非常關鍵- 而
default和catch的組合可以無論是沒有輸入、或是錯誤的輸入,都可以套用預設值,不會因為錯誤的輸入而導致程式出錯。
最後就可以在 Astro 頁面中使用解析後的參數了,而且參數一定會是符合預期的格式和型別:
<ul> <li>page: {params.page}</li> <li>type: {params.type}</li> <li>search: {params.search}</li> <li>category: {params.category}</li> <li>priceFrom: {params.priceFrom}</li> <li>priceTo: {params.priceTo}</li> <li>tags: {params.tags}</li> <li>sort: {params.sort}</li></ul>參考資料
- 作者:Lucas Yang
- 文章連結:https://star-note-lucas.me/posts/astro-zod-querystring
- 版權聲明:本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明出處。