參數驗證 middleware 可以用於 Actions 及事件的參數驗證。
Moleculer 預設使用與本框架同一個作者所開發的 fastest-validator
套件[2] 。
範例:快速使用,可以設為 "Fastest"
或 true
。
moleculer.config.js
module.exports = {
nodeID: "node-100",
validator: "Fastest"
}
範例:選項設定,更多選項請參閱[2]
moleculer.config.js
module.exports = {
nodeID: "node-100",
validator: {
type: "Fastest",
options: {
useNewCustomCheckerFunction: true,
defaults: { /*...*/ },
messages: { /*...*/ },
aliases: { /*...*/ }
}
}
}
要執行參數驗證之前,需要先在 action 定義好需要的參數名稱,然後再建立參數的驗證綱目。
範例:
const { ServiceBroker } = require("moleculer");
const broker = new ServiceBroker({
validator: true // 預設為啟用
});
broker.createService({
name: "say",
actions: {
hello: {
// 驗證器綱目
params: {
name: { type: "string", min: 2 }
},
handler(ctx) {
return "Hello " + ctx.params.name;
}
}
}
});
broker.call("say.hello").then(console.log)
.catch(err => console.error(err.message));
// -> throw ValidationError: "The 'name' field is required!"
broker.call("say.hello", { name: 123 }).then(console.log)
.catch(err => console.error(err.message));
// -> throw ValidationError: "The 'name' field must be a string!"
broker.call("say.hello", { name: "Walter" }).then(console.log)
.catch(err => console.error(err.message));
範例:驗證綱目
{
id: { type: "number", positive: true, integer: true },
name: { type: "string", min: 3, max: 255 },
status: "boolean" // 簡寫定義,更多請參閱[3]
}
Fastest Validator 在 v1.11.0 版後支援了異步客製化驗證器,只要在 moleculer.config.js
設定 useNewCustomCheckerFunction: true
來啟動這個功能,就可以利用它來建立客製化驗證函數。在 Moleculer 中,客製化驗證器函數可以使用 ctx
資訊,它會被放在 context.meta
中,你可以透過 ctx
來使用 context
、 service
、 broker
資源,因此你可以在驗證器中執行異步呼叫 (例如: ctx.call
)。
範例:啟用異步客製化驗證器
moleculer.config.js
module.exports = {
validator: {
type: "FastestValidator",
options: {
useNewCustomCheckerFunction: true,
defaults: { /*...*/ },
messages: { /*...*/ },
aliases: { /*...*/ }
}
}
}
範例:使用異步客製化驗證器
posts.service.js
module.exports = {
name: "posts",
actions: {
params: {
$$async: true,
owner: {
type: "string",
custom: async (value, errors, schema, name, parent, context) => {
// 由 meta 取得 ctx
const ctx = context.meta;
// 呼叫其它服務
const res = await ctx.call("users.isValid", {
id: value
});
if (res !== true)
errors.push({
type: "invalidOwner",
field: "owner",
actual: value
});
return value;
}
},
},
handler(ctx) {
// ...
}
}
};
事件也可以使用參數驗證,它的參數驗證綱目設定方式與 Actions 類似。
注意,驗證錯誤時並不會像 Actions 一樣返回給發送來源,它只會將錯誤紀錄在 log 或是在全域錯誤處理被捕獲。
mailer.service.js
module.exports = {
name: "mailer",
events: {
"send.mail": {
params: {
from: "string|optional",
to: "email",
subject: "string"
},
handler(ctx) {
this.logger.info("Event received, parameters OK!", ctx.params);
}
}
}
};
你也可以建立客製化的驗證器,官方建議可以參考 Fastest Validator[4] 的原始碼來修改,再實作 compile
、 validate
方法。
範例:建立 Joi 驗證器
使用前請安裝 joi[5] 套件
npm install joi --save
。
joi.validator.js
const BaseValidator = require("moleculer").Validators.Base;
const { ValidationError } = require("moleculer").Errors;
class JoiValidator extends BaseValidator {
constructor() {
super();
}
compile(schema) {
return (params) => this.validate(params, schema);
}
validate(params, schema) {
const res = schema.validate(params);
if (res.error)
throw new ValidationError(res.error.message, null, res.error.details);
return true;
}
}
module.exports = JoiValidator;
範例:使用 Joi 驗證器
greeter.service.js
const { ServiceBroker } = require("moleculer");
const Joi = require("joi");
const JoiValidator = require("./joi.validator");
let broker = new ServiceBroker({
logger: true,
validator: new JoiValidator // 使用 Joi 驗證器
});
// --- 測試 BROKER ---
broker.createService({
name: "greeter",
actions: {
hello: {
/*params: {
name: { type: "string", min: 4 }
},*/
params: Joi.object().keys({
name: Joi.string().min(4).max(30).required()
}),
handler(ctx) {
return `Hello ${ctx.params.name}`;
}
}
}
});
broker.start()
.then(() => broker.call("greeter.hello").then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// -> "name" is required ...
.then(() => broker.call("greeter.hello", { name: 100 }).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// -> "name" must be a string ...
.then(() => broker.call("greeter.hello", { name: "Joe" }).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// -> "name" length must be at least 4 characters long ...
.then(() => broker.call("greeter.hello", { name: "John" }).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data));
更多驗證器可以參考官方模組清單:
https://moleculer.services/modules.html#validation
[1] Parameter Validation, https://moleculer.services/docs/0.14/validating.html
[2] fastest-validator, https://github.com/icebob/fastest-validator
[3] fastest-validator shorthand-definitions, https://github.com/icebob/fastest-validator#shorthand-definitions
[4] Moleculer Fastest, https://github.com/moleculerjs/moleculer/blob/master/src/validators/fastest.js
[5] joi, https://joi.dev/