OneOf validation issue when schema has all fields optionals (not required)
See original GitHub issueWhat is going on?
AJV has oneOf keyword. Validators have to validate data against all schemas to establish validity according to this keyword.
I have validation schema that has one field (field ‘json’) which may be one of two schemas (schema ‘A’ and schema ‘B’). This two schemas have different fields and all of these fields are optional (not required).
const schema = {
type: 'object',
properties: {
json: {
type: 'object',
oneOf: [
{
title: 'A',
type: 'object',
properties: {
propA: {
type: 'number',
}
},
},
{
title: 'B',
type: 'object',
properties: {
propB: {
type: 'number'
}
},
}
]
}
},
required: ['json']
};
const data = {
json: {
propA: 123,
},
};
When I’m trying to validate object with this schema where I have field ‘json’ with type of one of the validation schemas (schema ‘A’ or schema ‘B’) validator says data.json should match exactly one schema in oneOf
.
You can minimal repository with all tests in index.js
. Start script with npm run start
.
All minimal repo content
Code
const Ajv = require("ajv");
const ajv = new Ajv({allErrors: true});
function test(data) {
const valid = validate(data)
if (valid) console.log("Valid!\n")
else console.log(`Invalid: ${ajv.errorsText(validate.errors)}\n`)
}
const schema = {
type: 'object',
properties: {
json: {
type: 'object',
oneOf: [
{
title: 'A',
type: 'object',
properties: {
propA: {
type: 'number',
}
}
},
{
title: 'B',
type: 'object',
properties: {
propB: {
type: 'number'
}
},
}
]
}
}
};
const validate = ajv.compile(schema)
const data = {
json: {},
};
data.json.propA = 123;
console.log(`1: Should be VALID (because it fits object 'A') but it is INVALID => INCORRECT VALIDATION`);
test(data);
data.json.propA = '123';
console.log(`2: Should be INVALID (because of 'propA' must be number) but it's VALID => INCORRECT VALIDATION`);
test(data);
delete data.json.propA;
data.json.propB = 123;
console.log(`3: Should be VALID (because it fits object 'B') but it is INVALID => INCORRECT VALIDATION`);
test(data);
data.json.propB = '123';
console.log(`4: Should be INVALID (because of 'propA' must be number) but it's VALID => INCORRECT VALIDATION`);
test(data);
schema.properties.json.oneOf[0].required = ['propA'];
delete data.json.propB;
console.log(`5: Should be VALID (because it fits object 'B' -> 'propB' optional) but it is INVALID => INCORRECT VALIDATION`);
test(data);
console.log(`6: Should be VALID (because it fits object 'A' -> 'propA' number) but it is INVALID => INCORRECT VALIDATION`);
data.json.propA = 123;
test(data);
console.log(`7: Should be INVALID (because it doesn't fit object 'A' -> 'propA' must be number) but it's VALID => INCORRECT VALIDATION`);
data.json.propA = '123';
test(data);
delete data.json.propA;
console.log(`9: Should be VALID (because it fits object 'B' -> 'propB' number) but it's INVALID => INCORRECT VALIDATION`);
data.json.propB = 123;
test(data);
console.log(`10: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) but it's VALID => INCORRECT VALIDATION`);
data.json.propB = '123';
test(data);
delete schema.properties.json.oneOf[0].required;
schema.properties.json.oneOf[1].required = ['propB'];
console.log(`11: Should be VALID (because it fits object 'A' -> 'propA' optional) and it's VALID => CORRECT VALIDATION`);
test(data);
console.log(`12: Should be VALID (because it fits object 'A' -> 'propA' number) and it's VALID => CORRECT VALIDATION`);
data.json.propA = 123;
test(data);
console.log(`13: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) and it's INVALID => CORRECT VALIDATION`);
data.json.propA = '123';
test(data);
delete data.json.propA;
console.log(`14: Should be VALID (because it fits object 'B' -> 'propB' number) but it's INVALID => INCORRECT VALIDATION`);
data.json.propB = 123;
test(data);
console.log(`15: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) but it's VALID => INCORRECT VALIDATION`);
data.json.propB = '123';
test(data);
Output
1: Should be VALID (because it fits object 'A') but it is INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
2: Should be INVALID (because of 'propA' must be number) but it's VALID => INCORRECT VALIDATION
Valid!
3: Should be VALID (because it fits object 'B') but it is INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
4: Should be INVALID (because of 'propA' must be number) but it's VALID => INCORRECT VALIDATION
Valid!
5: Should be VALID (because it fits object 'B' -> 'propB' optional) but it is INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
6: Should be VALID (because it fits object 'A' -> 'propA' number) but it is INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
7: Should be INVALID (because it doesn't fit object 'A' -> 'propA' must be number) but it's VALID => INCORRECT VALIDATION
Valid!
9: Should be VALID (because it fits object 'B' -> 'propB' number) but it's INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
10: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) but it's VALID => INCORRECT VALIDATION
Valid!
11: Should be VALID (because it fits object 'A' -> 'propA' optional) and it's VALID => CORRECT VALIDATION
Valid!
12: Should be VALID (because it fits object 'A' -> 'propA' number) and it's VALID => CORRECT VALIDATION
Valid!
13: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) and it's INVALID => CORRECT VALIDATION
Invalid: data/json/propA must be number, data/json/propB must be number, data/json must match exactly one schema in oneOf
14: Should be VALID (because it fits object 'B' -> 'propB' number) but it's INVALID => INCORRECT VALIDATION
Invalid: data/json must match exactly one schema in oneOf
15: Should be INVALID (because it doesn't fit object 'B' -> 'propB' must be number) but it's VALID => INCORRECT VALIDATION
Valid!
Default issue template
What version of Ajv are you using? Does the issue happen if you use the latest version? 8.6.3, Yes.
Ajv options object
const Ajv = require("ajv");
const ajv = new Ajv({allErrors: true});
JSON Schema
{
"type":"object",
"properties":{
"json":{
"type":"object",
"oneOf":[
{
"title":"A",
"type":"object",
"properties":{
"propA":{
"type":"number"
}
}
},
{
"title":"B",
"type":"object",
"properties":{
"propB":{
"type":"number"
}
}
}
]
}
}
}
Sample data
{
"json":{
"fieldA":123
}
}
Your code
const validate = ajv.compile(schema)
const valid = validate(data);
if (valid) console.log("Valid!\n");
else console.log(`Invalid: ${ajv.errorsText(validate.errors)}\n`)
Validation result, data AFTER validation, error messages
Invalid: data/json must match exactly one schema in oneOf
What results did you expect? Should be VALID (because it fits object ‘A’)
My Environment
Dependency | Version |
---|---|
Operating System | MacOS Big Sur 11.6 |
Node.js version | 14.17.3 |
NPM version | 4.4.3 |
AJV version | 8.6.3 |
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (5 by maintainers)
Top GitHub Comments
sorry misread your comment. Because it is valid against both subschemas, it is valid against the whole schema - that’s how oneOf is defined - it should be valid against exactly one subschema to be valid against oneOf - it’s exclusive OR operation
@epoberezkin thanks. I suppose “not supported” falls under this clause in the docs
Curious, is it not supported as “discriminator” is more of an OpenAPI thing?