Pattern properties not working as expected in JSON schema - json

I am struggling to get a simple definition for audio and video. The format should be of the form,
"audio": "These are mp3 artifacts" or
"digital": "These are .mp4 or .wav files"
I attempted as described in the documentation, using patternProperties with a regex which validates in a regex engine, like this, but it did not work.
{
"$schema": "https://json-schema.org/draft-07/schema#",
"description": "Definitions common to all most schemas",
"type": "object",
"additionalProperties":false,
"Definitions": {
"type": "object",
"patternProperties": {
"digital|audio": {"type": "string"}
},
"title": "Definitions"
}
}

You have an extra "Definitions" object. See https://json-schema.org/understanding-json-schema/reference/object.html#pattern-properties. This should work:
{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"patternProperties": {
"digital|audio": {
"type": "string"
}
}
}

{
"$schema": "https://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^digital$": {
"type": "string"
},
"^audio$": {
"type": "string"
}
}
}

Related

Enforcing properties of an object to be from the listed ones in a JSON Schema

How can I enforce the "object" property only to allow the listed properties be part of it and not something else, especially an empty key ""?
{
"type": "object",
"properties": {
"object": {
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
},
"property3": {
"type": "string"
}
},
"uniqueItems": true
}
}
}
I believe, what you are looking for is "additionalProperties": false.
Below is your schema with additionalProperties added. See here to try it out: https://www.jsonschemavalidator.net/s/RDGrQvL6
Note that I had to remove the extra "object" wrapper from your schema to make it work.
{
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
},
"property3": {
"type": "string"
}
},
"additionalProperties": false
}
Daniel's answer is correct and "additionalProperties": false is the right thing that I needed, but here is the code in terms of what I actually wanted to achieve with the nested object.
{
"type": "object",
"properties": {
"object": {
"type": "object",
"properties": {
"property1": {
"type": "string"
},
"property2": {
"type": "string"
},
"property3": {
"type": "string"
}
},
"uniqueItems": true,
"additionalProperties": false // will not allow any other property other than 'property1', 'property2' or 'property3' as part of the nested object "object".
}
}
}

How to write a valid JSON Schema for a document with only optional elements

I use JSON Schema to validate YAML and JSON configuration files. In one configuration file are all elements optional. But only is a limited set of elements is allowed.
What do I have to change in the given schema below, so that an empty file/document in case of JSON is also valid?
{
"$id": "https://snafu.com/api/service/publishing-mechanism/config-delta/1.0.0",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"description": "....",
"type": "object",
"additionalProperties": false,
"properties": {
"plans": {
"type": "object",
"additionalProperties": false,
"minProperties": 1,
"patternProperties": {
"^.*$": {
"type": "object",
"additionalProperties": false,
"properties": {
"description": {
"type": "string"
},
"validation": {
"type": "string",
"enum": ["auto", "manual"]
},
"security": {
"type": "string",
"enum": ["api_key"]
}
}
}
}
}
}
}
You can remove your patternProperties and just collapse that into additionalProperties -- which takes a schema, not just true/false. Because the patternProperties is a wildcard that matches everything, the additionalProperties there adds no value.
Otherwise, aside from the "minProperties": 1 which states that there cannot be zero properties, your definition already allows for optional properties at the top level, and at the "plans" level, all properties are optional as well. Use the required keyword to ensure that a property is actually present:
Reference: https://json-schema.org/understanding-json-schema/reference/object.html
So, after quite some time, here is the solution which is working for my project in production.
{
"$id": "https://snafu.com/api/service/publishing-mechanism/config-delta/1.0.0",
"$schema": "https://json-schema.org/draft/2019-09/schema",
"description": "....",
"$defs": {
"empty": {"type": "null"}
},
"type": "object",
"additionalProperties": false,
"properties": {
"plans": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^.+$": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"description": {
"minLength": 1,
"type": "string"
},
"security": {
"enum": ["api_key"],
"type": "string"
}
}
},
{ "$ref": "#/$defs/empty" }
]
}
}
},
{ "$ref": "#/$defs/empty" }
]
}
}
}
Here I use oneOf to have two mutually exclusive subschemas. One of the is all the possible properties, where one of them is required.
The second subschema has null as type. Therefore the only acceptable value for this schema is null.

JSON Schema - How to apply conditionals based on boolean and further restrict with additionalProperties: false?

Ansible picked up support for jsonschema, and I have a variety of use cases for it, but most all of them require conditionals. I have been reading the doc's for jsonschema and draft-7 if-then-else, and tried several permutations, and seemingly only get half of my target handled. Hoping someone can help pave the way with a practical example for me that I can deconstruct.
Two possibilities based on the bool in "send_notifications":
{
"capture_state": "value here",
"send_notifications": true,
"user_email_list": ["email#something.com", "email2#something.com"],
"host_info": [
{
"ansible_host": "192.20.xxx.xxx",
"ECRTicket": "1103035"
},
.... continued
]
}
or
{
"capture_state": "value here",
"send_notifications": false
}
Essentially, only allow, and require the properties shown in the examples based on the bool in "send_notifications", and unconditionally fail if its neither of these two schemas. I'll likely improve this more with patterns as well, but just these keys and types are a great start.
I had initially generated the following base schema to use as a reference to manipulate and add the conditionals, and perhaps it is something in this schema that conflicts with using conditionals and additionalProperties:false, but being new to jsonschema it's not immediately obvious to me, so reaching out for some assistance so I can put this to use more often. Any help would be appreciated, thank you for your time, new to posting on stack, if I can improve my question please let me know.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": [
"capture_state",
"send_notifications",
"user_email_list",
"host_info"
],
"properties": {
"capture_state": {
"type": "string"
},
"send_notifications": {
"type": "boolean"
},
"user_email_list": {
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
}
]
}
},
"host_info": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"required": [
"ansible_host",
"ECRTicket"
],
"properties": {
"ansible_host": {
"type": "string"
},
"ECRTicket": {
"type": "string"
}
},
"additionalProperties": false
}
]
}
}
},
"additionalProperties": false
}
Generally, you're going to have a hard time whenever you choose to restrict unknown properties. I'll assume you have a good reason and including it is worth it.
There are a couple ways to do this. I'm presenting it this way because it produces the best messages when a JSON instance fails schema validation.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"capture_state": { "type": "string" },
"send_notifications": { "type": "boolean" },
},
"required": ["capture_state", "send_notifications"],
"if": {
"properties": {
"send_notifications": { "const": true },
},
"required": ["send_notifications"]
},
"then": {
"properties": {
"capture_state": true,
"send_notifications": true,
"user_email_list": {
"type": "array",
"items": { "type": "string" }
},
"host_info": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ansible_host": { "type": "string" },
"ECRTicket": { "type": "string" }
},
"required": ["ansible_host", "ECRTicket"],
"additionalProperties": false
}
}
},
"required": ["user_email_list", "host_info"],
"additionalProperties": false
},
"else": {
"properties": {
"capture_state": true,
"send_notifications": true
},
"additionalProperties": false
}
}
additionalProperties only recognizes properties declared in the same sub-schema it appears in. That means you need to include some dummy properties entries so it knows about the properties that are declared elsewhere in the schema.
I assume ansible doesn't support more recent versions of JSON Schema than draft-07? If it does, you can use unevaluatedProperties instead of additionalProperties to avoid jumping through some of the hoops you have to with additionalProperties.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"properties": {
"capture_state": { "type": "string" },
"send_notifications": { "type": "boolean" },
},
"required": ["capture_state", "send_notifications"],
"unevaluatedProperties": false,
"if": {
"properties": {
"send_notifications": { "const": true },
},
"required": ["send_notifications"]
},
"then": {
"properties": {
"user_email_list": {
"type": "array",
"items": { "type": "string" }
},
"host_info": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ansible_host": { "type": "string" },
"ECRTicket": { "type": "string" }
},
"required": ["ansible_host", "ECRTicket"],
"additionalProperties": false
}
}
},
"required": ["user_email_list", "host_info"]
}
}
If anyone at Ansible happens to see this, draft 2020-12 includes unevaluatedProperties and will get a lot of implementation support as it is also included in OpenAPI 3.1.

JSON Schema Conditionals - Different Behaviour Between IDEs

I have two private IDE plugins that are generating JSON schemas to validate things. They are comprised of a bunch of definitions that are conditionally used with pattern regexs. The problem occurs in that the schema has different behaviours in IntelliJ and VS Code.
The schema is similar to below, however reduced and redacted:
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "array",
"additionalItems": true,
"definitions": {
"meat": {
"$id": "#/definitions/meat",
"type": "object",
"properties": {
"cut": {
"$id": "#/definitions/meat/cut",
"title": "cut",
"type": "string"
},
"fillet": {
"$id": "#/definitions/meat/fillet",
"title": "fillet"
},
"bones": {
"$id": "#/definitions/meat/bones",
"title": "bones",
"type": "string"
}
},
"required": [
"cut",
"fillet"
],
"additionalProperties": true
},
"fruit": {
"$id": "#/definitions/fruit",
"type": "object",
"properties": {
"pips": {
"$id": "#/definitions/fruit/pips",
"title": "pips",
"type": "string"
},
"stone": {
"$id": "#/definitions/fruit/stone",
"title": "stone"
},
"citrus": {
"$id": "#/definitions/fruit/citrus",
"title": "citrus",
"type": "string"
}
},
"required": [
"stone",
"pips"
],
"additionalProperties": true
}
},
"items": {
"$id": "#/items",
"type": "object",
"properties": {
"name": {
"$id": "#/items/name",
"type": "string",
"title": "Name"
},
"food": {
"$id": "#/items/food",
"type": "string"
}
},
"allOf": [
{
"if": {
"properties": {
"food": {
"pattern": "meat"
}
}
},
"then": {
"properties": {
"variants": {
"$ref": "#/definitions/meat"
}
}
}
},
{
"if": {
"properties": {
"food": {
"pattern": "fruit"
}
}
},
"then": {
"properties": {
"variants": {
"$ref": "#/definitions/fruit"
}
}
}
}
],
"additionalProperties": true
}
With YAML structure:
- name: orange
food: fruit
variants:
pips: true
So with food being fruit it will match, validate and suggest for that schema, and require stone and pips.
This works in VS Code. IntelliJ however, requires stone and pips correctly, however suggests keys from meat's properties.
This made me question if I have the correct implementation here - should I be using allOf, anyOf or oneOf here? I only need to match one. I also tried adding else: false, however that didn't change anything, and I still get suggestions for meat. When originally writing it, I think I found someone saying allOf will evaluate correctly as the unmatched patterns won't stop the merging of subschemas.
What I'm trying to identify is, is this an issue with my schema implementation, or a bug in IntelliJ's parsing of conditions? Or perhaps a bug in VS Code's parsing that has let me get away with faulty schemas.

Json Schema, Properties as Property not working

Maybe sounds confusing, I want to validate this model schema (should has $schema, title, properties and required field):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "My Schema",
"type": "object",
"properties": {
"myData": {
"type": "object",
"properties": {
"name_1": {
"type": "string"
},
"name_2": {
"type": "string"
},
"name_3": {
"type": "string"
}
}
}
},
"required": [
"myData"
]
}
I've already done this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"$schema": {
"type": "string"
},
"title": {
"type": "string"
},
"properties": {
"type": "object",
"enum": "myData"
},
"required": {
"type": "array",
"items": {
"myData": "string"
}
}
}
}
but this part is not working well:
"properties": {
"type": "object",
"enum": "myData"
},
Is possible to do this? or is prohibited to use those built schema words like: "required", "enum", "properties" as a property inside "properties"?.
Thanks in advance for helping me to understand this part :)
My fault, sorry. I've created wrong the json schema, it should be like this:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://jsonschema.net",
"type": "object",
"properties": {
"title": {
"type": "string"
},
"type": {
"type": "string"
},
"properties": {
"type": "object",
"properties": {
"myData": {
"type": "object"
}
}
},
"required": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
And works fine :)