Reputation: 629
I am using JsonSchema.Net (docs) to validate Json document against a prepared schema. Some of the properties are defined in the schema to be nullable (as described in the documentation {"oneOf":[{"type":"string"},{"type":"null"}]}
)
When I check a document against the schema some evaluation details for nullable properties will be returned as IsValid = false
with errors opposite of what is in the Json (e.g. "Value is "null" but should be "integer""
, or "Value is "number" but should be "null""
).
I would like to understand what I might be doing wrong in this case. And how may I filter such false-positives, so that if Json document is invalid, I could quickly find nodes that are the cause, and what is wrong with them.
Document Example:
{
"referenceNumber": "35366",
"storageZone": null,
"maxCount": null,
"length": 124.5
}
Document's Json Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Schema Example",
"$defs": {
"stringNullable": {
"oneOf": [
{ "type": "string" },
{ "type": "null" }
]
},
"integerNullable": {
"oneOf": [
{ "type": "integer" },
{ "type": "null" }
]
},
"numberNullable": {
"oneOf": [
{ "type": "number" },
{ "type": "null" }
]
}
},
"type": "object",
"properties": {
"referenceNumber": {
"type": "string"
},
"storageZone": {
"$ref": "#/$defs/stringNullable"
},
"maxCount": {
"$ref": "#/$defs/integerNullable"
},
"length": {
"$ref": "#/$defs/numberNullable"
}
}
}
Code Example:
[Test]
public void JsonSchemaAsserts()
{
var schema = JsonSchema.FromFile("./SchemaExample.json");
var jsonText = File.ReadAllText("./DataExample.json");
var json = JsonNode.Parse(jsonText);
var validationResult = schema.Evaluate(json, new EvaluationOptions() { OutputFormat = OutputFormat.List });
Assert.That(validationResult.IsValid, Is.True);
var validationErrors = validationResult.Details.Where(d => !d.IsValid && d.HasErrors).ToList();
Assert.That(validationResult, Is.Empty);
}
Upvotes: 1
Views: 401
Reputation: 3297
Because you are using oneOf
, there is always going to be a false
schema when more than one schema is validated.
If you want a cleaner way to write the same schema, you can use the array form of type
.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Schema Example",
"$defs": {
"stringNullable": {
"type": [
"string",
"null"
]
},
"integerNullable": {
"type": [
"integer",
"null"
]
},
"numberNullable": {
"type": [
"number",
"null"
]
}
},
"type": "object",
"properties": {
"referenceNumber": {
"type": "string"
},
"storageZone": {
"$ref": "#/$defs/stringNullable"
},
"maxCount": {
"$ref": "#/$defs/integerNullable"
},
"length": {
"$ref": "#/$defs/numberNullable"
}
}
}
This will give the following results
{
"valid": true,
"evaluationPath": "",
"schemaLocation": "https://json-everything.net/2f7acd351a#",
"instanceLocation": "",
"annotations": {
"title": "Schema Example",
"properties": [
"referenceNumber",
"storageZone",
"maxCount",
"length"
]
},
"details": [
{
"valid": true,
"evaluationPath": "/properties/referenceNumber",
"schemaLocation": "https://json-everything.net/2f7acd351a#/properties/referenceNumber",
"instanceLocation": "/referenceNumber"
},
{
"valid": true,
"evaluationPath": "/properties/storageZone",
"schemaLocation": "https://json-everything.net/2f7acd351a#/properties/storageZone",
"instanceLocation": "/storageZone",
"details": [
{
"valid": true,
"evaluationPath": "/properties/storageZone/$ref",
"schemaLocation": "https://json-everything.net/2f7acd351a#/$defs/stringNullable",
"instanceLocation": "/storageZone"
}
]
},
{
"valid": true,
"evaluationPath": "/properties/maxCount",
"schemaLocation": "https://json-everything.net/2f7acd351a#/properties/maxCount",
"instanceLocation": "/maxCount",
"details": [
{
"valid": true,
"evaluationPath": "/properties/maxCount/$ref",
"schemaLocation": "https://json-everything.net/2f7acd351a#/$defs/integerNullable",
"instanceLocation": "/maxCount"
}
]
},
{
"valid": true,
"evaluationPath": "/properties/length",
"schemaLocation": "https://json-everything.net/2f7acd351a#/properties/length",
"instanceLocation": "/length",
"details": [
{
"valid": true,
"evaluationPath": "/properties/length/$ref",
"schemaLocation": "https://json-everything.net/2f7acd351a#/$defs/numberNullable",
"instanceLocation": "/length"
}
]
}
]
}
Upvotes: 1