AnyOf vs type array - jsonschema

Are there any differences between the following two JSON schemas validations or do they validate the same data structure?
SomeProperty
{
"type": ["integer","string"]
}
SomeProperty
{
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
}

They are equivalent!
type
The value of this keyword MUST be either a string or an array. If it
is an array, elements of the array MUST be strings and MUST be unique.
String values MUST be one of the six primitive types ("null",
"boolean", "object", "array", "number", or "string"), or "integer"
which matches any number with a zero fractional part.
An instance validates if and only if the instance is in any of the
sets listed for this keyword.
https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.1.1
Notice the last section "...in any of..."

Related

A json Schema with an array of a $ref or an enum

I would like to have a Json Schema that would enforce an array of $ref and an enum of null. I have accidentally defined a tuple - not what I want. Here is my current schema (note I must use draft-04):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"version": "4.4.0",
"title": "myCollection",
"description": "Resume/CV",
"type": "object",
"properties": {
"EmploymentHistories": {
"type": "array",
"items": {
"oneOf": [
{
"$ref": "../../../Common/json/base/TextType.json#"
},
{
"enum": [
null
]
}
]
},
"additionalProperties": false
}
}
}
And here is an instance I would like:
{
"EmploymentHistories": [
{
"value": "String",
"languageCode": "aa"
},
{
"value": "String",
"languageCode": "aa"
},
null,
null
]
}
But I am getting an error on validation like:
File D:\Dev\Proj\Recruiting\json\resumecv\samples\Untitled5.json is not valid.
A value of type 'null' is not permitted here.
Reason: it must be of one of the following types (see below)
'string'
'object'
Hint: Either 'type' is present and doesn't contain 'null' or 'enum' is present and doesn't contain a value of type 'null'.
Error location: EmploymentHistories / 3
Details
Array item '2' is not valid.
Property 'EmploymentHistories' is not valid.
A value of type 'null' is not permitted here.
Reason: it must be of one of the following types (see below)
'string'
'object'
Hint: Either 'type' is present and doesn't contain 'null' or 'enum' is present and doesn't contain a value of type 'null'.
Error location: EmploymentHistories / 4
Details
Array item '3' is not valid.
Property 'EmploymentHistories' is not valid.
Any help is appreciated.n
This looks like a bug in the validator implementation you are using. It seems to be saying that "enum": [null] is not allowed in a schema. The error is incorrect. This should be perfectly fine. However, you can probably work around this bug by changing it to "type": "null", which should have the same effect.

Does Json Schema allow a property's definition to reference another property?

I'd like to create a JSON schema that restricts one property's values based on another property's values.
An example valid object might look like this:
{
"lookup": {
"foo": "string",
"bar": "number",
},
// properties in `values` must exist in `lookup`
"values": {
// `foo` must be a string
"foo": "string is OK",
// `bar` must be a number
"bar": 100
}
}
The idea is for the schema to enforce a relationship between the two properties.
{
"type": "object",
"properties": {
"lookup" : {
"type": "object",
"additionalProperties" : {
"type": "string",
"enum": ["string", "number"]
}
},
"values": {
"type": "object",
// - this value's properties must exist in `lookup`
// - if the property in `lookup` is set to `string`, the type here must be `string`; if the property in `lookup` is set to `number`, the type here must be `number`
}
}
}
This is possible in some cases. While you can't restrict a piece of data to certain values taken from other parts of the data (for example: using property X to provide a list of values that property Y can have), you can specify conditionals between parts of your schema.
requirement 1: this value's properties must exist in lookup -> not possible
requirement 2: if the property in lookup is set to string, the type here must be string; if the property in lookup is set to number, the type here must be number -> possible
See https://json-schema.org/understanding-json-schema/reference/conditionals.html for the various options available to you.
This is not possible with the standard specification of JSON Schema.

In JSON schema, define and reference a reusable enum type?

I noticed the following: Reusable enum types in json schema , which talks about defining a reusable enum type in JSON schema.
I would have assumed USING this reusable enum type would be trivial, simply specifying (in this case) the value of "MyEnum" for a "type" value.
I don't know if the results from Oxygen XML are authoritative, but I tried something like the following:
{
"$schema": "https://json-schema.org/draft/2019-09/schema#",
"type": "object",
"properties": {
"content": {"$ref": "#/definitions/content_type"}
},
"additionalProperties": false,
"definitions": {
"costCategory_type": {
"type": "object",
"enum": ["VH", "H", "M", "L"]
},
"allowedDevices_type": {
"type": "object",
"properties": {
"costCategory": {
"type": "costCategory_type"
},
On the line near the bottom of this, where I reference "costCategory_type", Oxygen gives me a syntax error, saying
#/definitions/allowedDevices_type/properties/costCategory/type: unknown type: [costCategory_type]
What am I missing?
Yes, the type keyword can only have values from the list null, boolean, object, array, string, number, integer. You can reference definitions with the $ref keyword:
...
"properties": {
"costCategory": {
"$ref": "#/definitions/costCategory_type",
}
}
(incidentally, your definition won't ever evaluate successfully as-is since you define it as being the "object" type, but the list of values in the enum are all strings.)

Using a $ref and other properties within a JSON Schema

In a JSON Schema is is valid to have a $ref and then other properties within the same schema, for example.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"title": "My schema",
"properties": {
"scripts": {
"$ref": "#/definitions/scriptsBase",
"description": "More docs.",
"minLength": 10
}
},
"definitions": {
"scriptsBase": {
"type": "string",
"description": "Base Description",
"minLength": 5
}
}
}
If this is allowable, then what are the rules when it comes to resolving properties defined in the $refed and the $refing schemas (in this example minLength and description. But potentially this could become much more complex if allOf etc where defined in both.
Found the answer in json schema property description and "$ref" usage, basically if a $ref exists all other properties are ignored.
https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03#section-3
Syntax
A JSON Reference is a JSON object, which contains a member named
"$ref", which has a JSON string value. Example:
{ "$ref": "http://example.com/example.json#/foo/bar" }
If a JSON value does not have these characteristics, then it SHOULD
NOT be interpreted as a JSON Reference.
The "$ref" string value contains a URI [RFC3986], which identifies
the location of the JSON value being referenced. It is an error
condition if the string value does not conform to URI syntax rules.
Any members other than "$ref" in a JSON Reference object SHALL be
ignored.

Have one property define the types in another array property, using JSON Schema?

Given this example JSON:
{
"type": "number",
"values": [ 34, 42, 99 ]
}
Is it possible to define JSON Schema that makes sure that the contents of
the values array are of the type specified in another property (in this example type)?
Above type is saying that the array values can only contain integers (using the specifier "number").
Or specify that values contains strings:
{
"type": "string",
"values": [ "hello", "world" ]
}
Yes you can use the "items" keyword. If it has a single value then that value is the schema for every element of the array.
{
"type": "array",
"items": { "type: "string" }
}
Assuming you're using a draft4 schema like most people do, section 8.2.3.1 of the specification states:
8.2.3.1. If "items" is a schema
If items is a schema, then the child instance must be valid against
this schema, regardless of its index, and regardless of the value of
"additionalItems".
Yes, but you will have to write an if/then block for each type you want to support.
The Understanding JSON Schema has a section on if/then/else: http://json-schema.org/understanding-json-schema/reference/conditionals.html
Here is an extract that explains how if/then/else works.
For example, let’s say you wanted to write a schema to handle
addresses in the United States and Canada. These countries have
different postal code formats, and we want to select which format to
validate against based on the country. If the address is in the United
States, the postal_code field is a “zipcode”: five numeric digits
followed by an optional four digit suffix. If the address is in
Canada, the postal_code field is a six digit alphanumeric string where
letters and numbers alternate.
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada"]
}
},
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
},
"else": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
}
For each type you want to support, you would need to write if/then object, and wrap all of them in an allOf.