mock-restful-api
Version:
This is dev support mock RESTful API. Refer to django-rest-framework implementation.
132 lines (125 loc) • 4.05 kB
JavaScript
const Joi = require("joi");
const utils = require("./utils.js");
const logger = require("./logger.js");
const { LookupEnum, ALLOW_METHODS } = require("./enums.js");
const handleValidateResult = result => {
if (result.error) {
const errMsgs = [];
result.error.details.forEach(err => {
// logger.error(`validate error ==> ${err.message}`);
errMsgs.push(err.message);
});
logger.error("validate error details:\n" + JSON.stringify(result.error.details, null, 2));
throw Error(errMsgs);
}
};
const buildJoiSchema = rules => {
let schema = {};
for (let key in rules) {
let item = rules[key];
try {
let rule = Joi[item.type]();
for (let attr in item) {
if (attr === "type") {
continue;
}
if (rule[attr]) {
// 函数存在则调用
const value = item[attr];
if (utils.isAbsBoolean(value)) {
if (value === true) {
// 例如 required: true 的场景
rule = rule[attr]();
}
} else {
if (utils.isArray(value)) {
rule = rule[attr](...value);
} else {
if (item.type === "string" && attr === "pattern") {
rule = rule.pattern(new RegExp(value));
} else {
rule = rule[attr](value);
}
}
}
}
}
schema[key] = rule;
} catch (err) {
logger.error(`The rule is illegal, not support: ${JSON.stringify(item)}`);
logger.error(err);
}
}
return Joi.object(schema).unknown();
};
const validateSubmitData = (data, rules, partial = false) => {
if (!utils.isDict(data)) {
throw Error("The resutful created data submitted by post can only be a dictionary.");
}
if (!utils.isDict(rules)) {
return data;
}
let myRules = {};
if (partial) {
for (let fieldName in rules) {
// 部分更新的情况下只校验表单传递了的字段
if (data[fieldName] !== undefined) {
myRules[fieldName] = rules[fieldName];
}
}
} else {
myRules = { ...rules };
}
const joiSchema = buildJoiSchema(myRules);
const result = joiSchema.validate(data);
handleValidateResult(result);
return result.value;
};
const validateConfig = data => {
const schema = Joi.object({
restful: Joi.string(),
page_size: Joi.number().min(1).integer(),
filter_fields: Joi.object().pattern(Joi.string(), Joi.array().items(Joi.string().valid(...LookupEnum.map(member => member.value)))),
search_fields: Joi.array().items(Joi.string()),
ordering_fields: Joi.array().items(Joi.string()),
ordering: Joi.array().items(Joi.string()),
pk_field: Joi.string(),
rules: Joi.object().pattern(Joi.string(), Joi.object({ type: Joi.string().required() }).unknown()),
rows: Joi.array().items(Joi.object()),
actions: Joi.array().items(
Joi.object({
method: Joi.string().valid(...ALLOW_METHODS).required(),
url_path: Joi.string().required(),
detail: Joi.boolean(),
response: Joi.object({
code: Joi.number().min(1).integer(),
headers: Joi.object().pattern(Joi.string(), Joi.string()),
json: Joi.alternatives().try(Joi.object(), Joi.array()),
file: Joi.string(),
text: Joi.string(),
}).unknown(),
})
),
apis: Joi.array().items(
Joi.object({
method: Joi.string().valid(...ALLOW_METHODS).required(),
path: Joi.string().required(),
response: Joi.object({
code: Joi.number().min(1).integer(),
headers: Joi.object().pattern(Joi.string(), Joi.string()),
json: Joi.alternatives().try(Joi.object(), Joi.array()),
file: Joi.string(),
text: Joi.string(),
}).unknown(),
})
),
}).unknown();
const result = schema.validate(data);
handleValidateResult(result);
return result.value;
};
module.exports = {
handleValidateResult,
validateSubmitData,
validateConfig,
};