日常作業中免不了頻繁處理 GET/POST 的入參,你當然可以每個 action 中都重復地去做這些事情,
- 從 query 或 body 取出入參,
- 對可選的入參進行判空,
- 處理入參的類型轉換,
- 對入參進行邏輯校驗,數字是否超限,類型是否非法等...
但這些通用的邏輯可通過抽取到插件或服務中,避免代碼冗余和重復勞動。
egg-validation
Egg.js 中可通過 egg-validation 插件來減少這部分的工作量。通過該插件,上面大部分工作可轉成簡單的配置。
安裝插件
$ yarn add egg-validate
配置插件
啟用:
config/plugin.ts
const plugin: EggPlugin = {
// ...
validate: {
enable: true,
package: 'egg-validate',
},
// ...
};
export default plugin;
配置插件:
config/config.default.ts
export default (appInfo: EggAppInfo) => {
const config = {} as PowerPartial<EggAppConfig>;
// ...
config.validate = {
convert: true,
widelyUndefined:true
};
// ...
};
其配置項為 node-modules/parameter 的所有可用配置項,因為該插件其實就是后者的 Egg.js 封裝。
convert會對入參進行轉換,建議開啟。舉個例子,使用表單中默認的 submit 類型按鈕提交表單時,提交過來的往往是序列化后的字符串,那些期望是數字類型的字段就會始終驗證不過。而開啟此項后,會對入參按希望的類型進行轉換。widelyUndefined開啟后,會把空字符串,NaN,null這些轉成undefined,將這些異常的數據進行了統一,方便后續處理。
使用
插件在 app 及 context 上擴展了 validator 對象,通過調用 validator.validate(rules,data) 來進行驗證。
比如接收一個名為 name 的字符串入參:
app/controller/home.ts
const errors = this.app.validator.validate({ name: 'string' }, this.request.body);
if (errors) {
this.ctx.body = errors;
}
驗證規則
validate 第一個參數為規則,它是個對象。其每個字段對應同名的入參。字段的值可以是簡單的字符串,指定字段的類型,也可以是對象,在這個對象里進行更加詳細的規則指定。
const rules = {
param1: 'string', // 必填的字符串入參
param2: 'string?', // 可選的字符串入參
param3: {
type: 'int', // 整形入參
required: false, // 該入參可選
min: 0, // 該入參的最小值
max: 10, // 該入參的最大值
},
};
規則默認入參是必填的,對於可選的入參,可通過在類型后加問號,與 TypeScript 類似,也可以顯式指定 required: false。
預設可用的參數類型參見 parameter。
針對參數的規則配置,根據參數的類型,有不同的配置頂,比如對於數字類型,可配置其最大最小值;對於枚舉,可定義其候選值,一旦入參不在這些值之內,便驗證不通過。每種類型可用的配置項參見 parameter。
自定義驗證規則
如果上面文檔中預設的這些類型無法滿足需求,可通過 validator.addRule(type,checker) 自定義規則來擴充。
其中 type 為新增規則的類型名, checker 為用來校驗的正則或方法。如果是個方法,其入參為規則本身及需要校驗的數據,文檔里沒有體現其入參,可參考源碼。
checker.call(self, rule, obj[key], obj);
比如增加一種類型為 jsonString 的驗證規則,限定入參必需為合法的 JSON 數據。
app.ts
export default (app) => {
app.validator.addRule('jsonString', (_rule, value) => {
try {
JSON.parse(value);
} catch (err) {
return 'must be json string';
}
});
};
示例代碼
一個可本地運行調試,配合了預設的驗證規則及自定義的規則的示例,完整代碼可在 GitHub 找到。
結論
寫了過多的重復的代碼后,比如這種入參的校驗,就應該想想如何優雅地來處理這些重復的工作,無論是自己造輪子,還是找輪子。入參的校驗如此之常見,進而,甚至可以去追求一套前后台通用的校驗邏輯,將瀏覽器端的 JavaScript 與 Node.js 的邏輯進行統一。
