Reputation: 3698
I am using Ajv in my project. I am trying to add a custom keyword by the help of ajv.addKeyword
api. I am able to add keyword by doing this (borrowed from docs):
var ajv = new Ajv({
$data: true
});
ajv.addKeyword('range', {
type: 'number',
compile: function(sch, parentSchema) {
var min = sch[0];
var max = sch[1];
return parentSchema.exclusiveRange === true ? function(data) {
return data > min && data < max;
} : function(data, dataPath, parentData, parentDataProperty) {
return data >= min && data <= max;
}
}
});
var schema = {
"properties": {
"smaller": {
"type": "number"
},
"larger": {
"type": "number",
"range": [2, 10]
}
}
};
var validData = {
smaller: 15,
larger: 17
};
let validateData = ajv.compile(schema);
validateData(validData);
console.log('Errors after validations --> ', validateData.errors)
Everything is working fine. Now I need to use $data
cause data for my custom field will be the value of some other field. To achieve it this is what I tried with my schema:
var schema = {
"properties": {
"smaller": {
"type": "number"
},
"larger": {
"type": "number",
// "range": [2, 10],
"range": {
"$data": "1/myRange" // referencing to myRange
}
},
"myRange": {
type: "array",
items: {
type: "number"
}
}
}
};
But it looks likes custom fields are not supported with $data
ref yet. As mentioned in the docs, only following fields are supported for $data ref.
$data reference is supported in the keywords: const, enum, format, maximum/minimum, exclusiveMaximum / exclusiveMinimum, maxLength / minLength, maxItems / minItems, maxProperties / minProperties, formatMaximum / formatMinimum, formatExclusiveMaximum / formatExclusiveMinimum, multipleOf, pattern, required, uniqueItems.
One way to get the value is, I use parameters of validate function data, dataPath, parentData, parentDataProperty
and write logic to extract value of field defined by $data
ref. But I am not sure this is a right way to achieve it or not. Can anyone please help me on this? Here's the plunkr to play. Thanks.
Upvotes: 1
Views: 3706
Reputation: 1214
Also for anybody now finding this, just to add to @hitesh's answer if you want to add errors to the custom keyword you do so by attaching them to the validation function. I have included Hitesh's answer with the update for adding an error message
// Code goes here
console.clear();
var ajv = new Ajv({
$data: true
});
ajv.addKeyword('range', {
type: 'number',
errors: true,
$data: true, // important part
validate: function myCustomKeyword(schema, data, parentSchema) {
if (
myCustomKeyword["errors"] === undefined ||
myCustomKeyword["errors"] === null
)
myCustomKeyword["errors"] = [];
const {
exclusiveRange: isExclusive
} = parentSchema;
const [min, max] = schema;
if (isExclusive) {
return data > min && data < max;
} else {
myCustomKeyword["errors"].push({
keyword: "range",
message: `range message`,
params: {
keyword: "range",
},
});
}
return data >= min && data <= max;
}
});
var schema = {
"properties": {
"smaller": {
"type": "number",
"maximum": {
"$data": "1/larger"
}
},
"larger": {
"type": "number",
// "range": [2, 10],
"range": {
"$data": "1/myRange"
},
"exclusiveRange": true
},
"myRange": {
type: "array",
items: {
type: "number"
}
}
}
};
var validData = {
smaller: 3,
larger: 7,
myRange: [2, 10]
};
let validateData = ajv.compile(schema);
validateData(validData);
console.log(ajv);
console.log('Errors after validations --> ', validateData.errors)
Upvotes: 0
Reputation: 3698
After digging documentation for a while finally I made it working. It's always good to share the solution for posterior readers. This is what I have done:
// Code goes here
console.clear();
var ajv = new Ajv({
$data: true
});
ajv.addKeyword('range', {
type: 'number',
errors: true,
$data: true, // important part
validate: function(schema, data, parentSchema) {
const {
exclusiveRange: isExclusive
} = parentSchema;
const [min, max] = schema;
if (isExclusive) {
return data > min && data < max;
}
return data >= min && data <= max;
}
});
var schema = {
"properties": {
"smaller": {
"type": "number",
"maximum": {
"$data": "1/larger"
}
},
"larger": {
"type": "number",
// "range": [2, 10],
"range": {
"$data": "1/myRange"
},
"exclusiveRange": true
},
"myRange": {
type: "array",
items: {
type: "number"
}
}
}
};
var validData = {
smaller: 3,
larger: 7,
myRange: [2, 10]
};
let validateData = ajv.compile(schema);
validateData(validData);
console.log(ajv);
console.log('Errors after validations --> ', validateData.errors)
The salient option is $data
in definition.It needs to be set true
. Here's the working plunkr
Upvotes: 10