Documentation based on JSON Schema - json

I'd like to use my JSON schemas to generate the documentation.
In the example below, I want to list all combinations ErrorNumber/ErrorMessage available in my output messages in JSON.
But I can't find a way on the object level, my attempts with "examples" or "enum" failed.
Does anyone have a solution?
{
"type": "object",
"required": [
"ErrorNumber",
"ErrorMessage"
],
"properties": {
"ErrorNumber": {
"$id": "#root/ErrorNumber",
"type": "integer"
},
"ErrorMessage": {
"$id": "#root/ErrorMessage",
"type": "string"
}
}
}

Did you mean to write "$ref" where you use "$id" in the example?
Where exactly did you have problems with enum? The following works fine for me with a draft-2020-12 Validator (and after removing your "$id"!):
{
// ... your JSON here ...
"enum": [
{"ErrorNumber": 200, "ErrorMessage": "OK"},
{"ErrorNumber": 404, "ErrorMessage": "Not found."}
// ...
]
}
Different approaches, in case you still can change that:
If your error numbers start at 0 and are contiguous, then an Array of messages might serve your purpose.
Alternatively an object with numerical keys might:
{
"200": "OK",
"404": "Not found."
}

Related

Is there a Json schema validation implementation give all the missing required fields?

Normally, when validate a complicated json object, if an embedded field is required but the parent which is also required is missing, a validator only give the result saying the parent is required.
Wondering if there is a way (an implementation of json schema validator) to find all the mandatory fields (in the leaves of a json object) by applying a json schema validation?
Using https://www.jsonschemavalidator.net/
With schema
{
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "object",
"required": [
"firstName",
"secondName"
],
"properties": {
"firstName": {
"type": "string"
},
"secondName": {
"type": "string"
}
}
}
}
}
To validate an empty json object {}.
Can only get one error Message:
Required properties are missing from object: name.
Schema path: #/required
Can a validator give all the required fields including first and second names back in the error message?

Can't validate a json with a schema using an external schema file

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:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/test-json?view=powershell-7.2&WT.mc_id=DT-MVP-5004831
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
I edit the question to leave what worked for me:
Change storages.json like this:
"properties": {
"securities": {
"$ref": "securities1.json#/securities"
},
"name": {
"type": "string"
},
"comment": {
"type": "string"
}
}
Change securities.json as:
{
"securities": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"kind",
"comment"
],
"properties": {
"comment": {
"type": "string"
},
"kind": {
"type": "string"
}
}
}
}
}
And of course I applied all changed suggested in the post
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 just storages.json, or even better, a full URI like https://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 $ref is wrong. #/schemas/securities.json is 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 $id in securities.json as well. This may be what is producing the error.
At #/properties/storages, you have "type": "array" and "additionalProperties": false. Maybe you meant additionalItems? additionalProperties only works on objects. (I also see this in securities.json at #/properties/securities.)
Your use of items is 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 for items; 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 $id in several places, which replaced draft 4's id in 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 $id to the root so that the $ref in 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 anyOf but only declare a single schema. You don't need this. Just move the keywords in that subschema up to where the allOf is.
{
"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.
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.

JSON Schema Validation validate array items not working

Here is the thing I'm trying to validate:
[REMOVED AFTER EDIT - PLEASE SEE EDIT BELOW FOR UP TO DATE CODE]
This should fail because only the item that should be acceptable here is "merchants" - but the validation doesn't fail. It passes.
I've can't work this out. I've tried a few approaches and it's got me nowhere.
What is wrong here?
---------------------- EDIT ----------------------------
I've been asked to provide more code. Here is the payload I need to validate. It's in PHP.
$payload = (object) [];
$payload->query_string = (object) [];
$payload->query_string->include = (object) [
"merchant_channel",
"merchant",
];
Here is the line that will run the validator:
$this->validator->validate(
$payload,
['$ref' => 'file://Schemas/the-json-file.json']
);
And here is the file that I'm running the validator against:
{
"type": "object",
"properties": {
"query_string": {
"type": "object",
"properties": {
"include": {
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"allOf": [
{
"type": "string",
"enum": [
"language"
]
}
]
}
}
}
}
}
}
}
}
I'm using this package:
https://github.com/justinrainbow/json-schema
This package is quite simply....
A PHP Implementation for validating JSON Structures against a given Schema.
You shouldn't have to know PHP to able to answer my original question which is specific to JSON Schema Validation!
Please don't comment/answer saying something like "You've missed a quote" or "You've missed a closing bracket". Obviously I've had to cut this code down so I can post it on Stack Overflow.
It lacks starting and ending curly braces.

Reuse pattern in JSON schema

Is it possible to define a regex once and re-use it? I have a few pretty complex regexes which I would like to use as the pattern for the value of a large number of properties of various different object in my schema. Doing Copy paste of this looks like asking for trouble further down the line, but I can't seem to find a suitable re-use example anywhere.
Cut down schema which illustrates what I want to do.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"patterns": {
"fqdn_or_ipaddress": "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+[a-zA-Z]{2,63}$)||(((?:^[0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])$)|(^\\*$))",
},
"properties": {
"server_hostname" : {
"type":"string",
"pattern": {"#ref", "#/patterns/address"},
},
"proxy_hostname" : {
"type":"string",
"pattern": {"#ref", "#/patterns/address"},
}
}
}
Doesn't validate here http://www.jsonschemavalidator.net/ because "pattern" is not a string. Is this a hole in the re-use. I've looked at patternProperties, but that seems to solve completely different use case.
You can only $ref a schema. You would need to do something like this.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"server_hostname" : {
"$ref": "#/definitions/fqdn_or_ipaddress",
"description": "The server hostname"
},
"proxy_hostname" : {
"allOf": [{ "$ref": "#/definitions/fqdn_or_ipaddress" }],
"description": "The proxy hostname"
}
},
"definitions": {
"fqdn_or_ipaddress": {
"type": "string",
"pattern": "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+[a-zA-Z]{2,63}$)||(((?:^[0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])$)|(^\\*$))"
}
}
}
EDIT
I added two examples of how to extend from a $ref. In the first, you can just add the description. It will be ignored, but it is not an error. Since description is just a meta-data keyword, this shouldn't be a problem.
In the second example, you can use allOf to wrap the $ref and you can add whatever keywords you need (even non-meta data keywords).
This answer highlights key structure for reusing the defined pattern. However, the example does not validate as:
The definition is given as part of the object reference with "definitions" whereas the "$ref" path is referencing a "patterns" definition that is nowhere to be found.
The pattern definition key is provided as "fqdn_or_ipaddress" whereas the paths in the properties refer to a "fqn_or_ipaddress" which is not defined.
Following is the corrected sample that passes the validation in the JSON schema validator:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"server_hostname" : {
"$ref": "#/definitions/fqdn_or_ipaddress",
"description": "The server hostname"
},
"proxy_hostname" : {
"allOf": [{ "$ref": "#/definitions/fqdn_or_ipaddress" }],
"description": "The proxy hostname"
}
},
"definitions": {
"fqdn_or_ipaddress": {
"type": "string",
"fqdn_or_ipaddress": "(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?<!-)\\.)+[a-zA-Z]{2,63}$)||(((?:^[0-9])(?:(?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})[.](?:25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2}))(?![0-9])$)|(^\\*$))"
}
}
}

JSON schema for payloads accepted vs objects returned

I'm fleshing out schemas for a RESTful web service, and I'm a bit stumped on one small thing. Imagine if I have the following schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"urn": {
"type": "string"
}
}
}
Since the URN is generated by my service, I don't want to accept it in the client request. So urn is not included in the required array. However, it IS required in the response, so I can't use this schema to validate the response my service gives. I'd prefer not to have to use two different schemas and have to keep them in sync.
Is there a way to use a single schema to strictly model both cases? Or, if I need to use two schemas, is there a way to reference a common structural schema and just override the required field from my request and response schemas?
This is a known problem and there is no good way to handle it.
The only way to keep it to one schema is to not include the server generated properties in the required array and do additional checks on the server side to validate those properties.
No, there is no way to override a schema keyword. JSON Schema keywords always adds constraints to the set. You need to start with the common schema and extend from there using allOf.
Here is an example of the kind of thing you will need to do.
Creation Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/create-my-schema",
"type": "object",
"required": ["name"]
"properties": {
"name": {
"type": "string"
}
}
}
Full Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/my-schema",
"allOf": [{ "$ref": "http://example.com/create-my-schema" }],
"required": ["urn"],
"properties": {
"urn": {
"type": "string"
}
}
}
If you don't care about the human readability of the schemas, this approach is fine. Otherwise, some people have opted to dynamically build schemas on the server-side so the resulting schemas may have duplication, but the code doesn't.
You can use dynamic schema with the use of "oneOf"
{
"type" : "object",
"required" : ["name"],
"properties" : {
"name" : {
"oneOf" : [{
"$ref" : "#/definitions/withURN"
}, {
"$ref" : "#/definitions/withoutURN"
}
]
}
},
"definitions" : {
"withURN" : {
"properties" : {
"name" : {
"type" : "string"
},
"urn" : {
"type" : "string"
}
}
},
"withoutURN" : {
"properties" : {
"name" : {
"type" : "string"
}
}
}
}
}
for some example have a look: http://json-schema.org/example2.html
also this discussion thread: How to use dependencies in JSON schema (draft-04)