My issue
I need to validate a json file from a Json Schema. I have a main schema and this schema should load an external schema file to validate some part of the json.
For different reasons I can't merge them. I do need 2 schema file.
I am using a $ref statement as proposed in this doc:
but whatever I try I have this error:
Cannot parse the JSON schema.
What I need
What is the right schema syntax to do this in my case.
Test case
I have this directories on my disk:
.
test.ps1
----/jsons
params.json
----/schemas
securities.json
storages.json
I run validation from this pretty simple PowerShell (test.ps1):
# read json param
$testFile = Get-Content "./jsons/params.json" -Encoding UTF8 | convertfrom-json -Depth 50
$testee = $testFile.parameters | convertto-json
# read json schema
$schemasFile = (Get-ChildItem -Path "./schemas/storages.json").FullName
# test json from schema
$result = $testee | Test-Json -SchemaFile $schemasFile
$result
My json (params.json):
{
"parameters": {
"storages": [
{
"comment": "Very important storage",
"name": "fdlmsto"
}
],
"securities": [
{
"comment": "Critical rule",
"kind": "MSI"
}
]
}
}
The main schema (storages.json):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": [
"storages"
],
"properties": {
"storages": {
"$id": "#/properties/storages",
"type": "array",
"additionalProperties": false,
"items": [
{
"$id": "#/properties/storages/items",
"type": "object",
"additionalProperties": false,
"required": [
"name",
"comment"
],
"properties": {
"$ref": "#/schemas/securities.json",
"name": {
"type": "string",
"$id": "#/properties/storages/items/properties/name"
},
"comment": {
"type": "string",
"$id": "#/properties/storages/items/properties/comment"
}
}
}
]
}
}
}
and the child schema (securities.json):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"required": [
"securities"
],
"properties": {
"securities": {
"$id": "#/properties/securities",
"type": "array",
"additionalProperties": false,
"items": {
"$id": "/properties/securities/items",
"anyOf": [
{
"$id": "#/properties/securities/items/anyOf/0",
"type": "object",
"additionalItems": false,
"additionalProperties": false,
"required": [
"kind",
"comment"
],
"properties": {
"comment": {
"type": "string",
"$id": "#/properties/securities/items/anyOf/0/properties/comment"
},
"kind": {
"type": "string",
"$id": "#/properties/securities/items/anyOf/0/properties/kind"
}
}
}
]
}
}
}
}
What I tested
I tested several syntaxe for $ref:
#/schemas/securities.json
./schemas/securities.json
/schemas/securities.json
....
I also tried to set the schema in the repository of test.ps1
I checked that this is the securities section that don't work
Thank you
CodePudding user response:
It appears that the powershell cmdlet is powered by NJsonSchema, which at this stage doesn't support JSON Schema draft 2020-12.
There are several issues I see.
storages.json
- "$schema": "https://json-schema.org/draft/2020-12/schema" declares this is a draft 2020-12 schema. As your schema doesn't use any 2020-12 features, I'd suggest using draft 7 as it'll definitely be supported by NJsonSchema.
- Your schema is declaring itself to be the meta-schema with
"$id": "https://json-schema.org/draft/2020-12/schema". The meta-schema is a special schema that validates other schemas. What you probably want here is juststorages.json, or even better, a full URI likehttps://examp.le/schemas/storages.json. It's just an identifier though; it doesn't need to be downloadable. - Remove the internal
$ids. They're only specifying relative location and not providing any more detail. This kind of thing is generally calculated at runtime. - Your
$refis wrong.#/schemas/securities.jsonis going to try to search for this location inside the current schema. You need a full URI here, and you'll want to declare that same URI as$idin securities.json as well. This may be what is producing the error. - At
#/properties/storages, you have"type": "array"and"additionalProperties": false. Maybe you meantadditionalItems?additionalPropertiesonly works on objects. (I also see this in securities.json at#/properties/securities.) - Your use of
itemsis an array. This will only validate the first item. I think you're wanting to validate all the items. If so, just use the schema as the value foritems; don't wrap it in an array. (also seen in securities.json)
securities.json
- This schema uses draft 4, which is quite old and a bit incompatible with later drafts. Specifically, I see it's using
$idin several places, which replaced draft 4'sidin draft 6. Since draft 4 doesn't recognize$id, it'll probably ignore them. Moreover,$ref-ing between drafts isn't something that's required (or perhaps even addressed) by the specification. (I added some tests to the test suite around this only about a week ago.) As with storages.json I'd suggest using draft 7 here. - As mentioned above, you'll want to add an
$idto the root so that the$refin storages.json can identify this schema properly. - As with storages.json, remove the interal
$ids; they're not providing any additional function. - You use an
anyOfbut only declare a single schema. You don't need this. Just move the keywords in that subschema up to where theallOfis.{ "type": "object", "allOf": [ { ... } ] } // becomes { "type": "object", ... }
Sorry this sounds like a pile-on. I realize you might be new with JSON Schema. The learning curve can be pretty steep.
Instead of the documentation provided by MS, I'd use Understanding JSON Schema for how to write schemas. Use the MS docs only for how to use the cmdlet.
CodePudding user response:
Just to add one point to the excellent answer above: the array form of items is not valid in 2020-12 anyway - it was replaced with prefixItems.
But the advice to use draft-07 throughout is the right advice, as is the advice to use the schema form of items anyway.
