Json schema validating wrong instance as true - json

I have the following schema and I'm having a hard time trying to understand why it is not working.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://yourdomain.com/schemas/myschema.json",
"title": "Product",
"description": "A product in the catalog",
"type": "object",
"properties": {
"transitions" : {
"description": "defines the transitions to another state",
"type": "object",
"patternProperties": {
"^[0-9]+$": {
"description": "defines a transition for an specific node",
"type":"object",
"properties": {
"next": {
"description": "id of the next transition",
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
},
"action": {
"description": "id of the transitions action",
"type":"string"
}
}
}
},
"additionalProperties": false
}
},
"required": ["transitions"]
}
For example, as you can see in the schema, this particular json instance should comply with one of next property definitions
"transitions": {
"1": {
"action": "1_input",
"next": {
"test de una novedad": "2"
}
}
}
}
schema for property
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
But I got these error messages in an online validator https://www.jsonschemavalidator.net/,
Message:
JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 1, 2.
Schema path:
http://yourdomain.com/schemas/myschema.json#/properties/transitions/patternProperties/^[0-9]+$/properties/next/oneOf
Message:
Invalid type. Expected String but got Object.
Schema path:
http://yourdomain.com/schemas/myschema.json#/properties/transitions/patternProperties/^[0-9]+$/properties/next/oneOf/0/type
I don't see how it can be a match with two of the definitions.
Has anyone had a similar situation?
Thanks in advance

Your problem is with the definition of the oneOf
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
For "test de una novedad": "2" both second and third element are objects with no property restriction, so it matches both.
To fix this you could try merging both if you don't mind possibly having an object validated with both properties:
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
},
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]
Or you could add additionalProperties: false in one or both.
"oneOf": [
{
"type":"string"
},
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^[\\<\\>\\=\\!\\=\\>\\<]\\_[0-9]+$" : {
"type":"string"
}
}
},
{
"type": "object",
"additionalProperties": false,
"patternProperties": {
"^\\w+( +\\w+)*$" : {
"type":"string"
}
}
}
]

Related

Validation JSON subschema definition based on ENUM value

I'm trying to validate and report errors of a JSON schema for a build process.
Based on the type enum I want to validate against a specific subschema and report errors for that schema.
If the type attribute is "weblogic" then I only want to validate against the "weblogic" subschema definition. And do the same if the type is tomcat
This is my current schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "#",
"type": "object",
"title": "The Root Schema",
"required": [
"middleware"
],
"properties": {
"middleware": {
"$ref": "#/definitions/middleware"
}
},
"definitions": {
"middleware":{
"type": "array",
"items": {
"oneOf":[
{"$ref": "#/definitions/weblogic"},
{"$ref": "#/definitions/tomcat"}
],
"required": ["type","buildInfo"]
}
},
"weblogic": {
"properties": {
"type": {"const": "weblogic"},
"buildInfo": {
"properties": {
"adminSslPort": {
"type": "integer"
}
},
"additionalProperties": false,
"required": ["adminSslPort"]
}
}
},
"tomcat":{
"properties": {
"type": {"const": "tomcat"},
"buildInfo":{
"properties": {
"classpath": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["classpath"]
}
}
}
}
}
And my JSON payload
{
"middleware":[
{
"type": "weblogic",
"buildInfo":{
"adminSslPort": 7002
}
},
{
"type": "tomcat",
"buildInfo":{
}
}
]
}
Now I expect this to fail since the buildInfo object is missing the classpath attribute, and it does fail validation.
But the errors I get back include the validation errors against the "weblogic" definition.
[
{
"pointerToViolation": "#/middleware/1",
"causingExceptions": [
{
"schemaLocation": "#/definitions/weblogic",
"pointerToViolation": "#/middleware/1",
"causingExceptions": [
{
"schemaLocation": "#/definitions/weblogic/properties/buildInfo",
"pointerToViolation": "#/middleware/1/buildInfo",
"causingExceptions": [],
"keyword": "required",
"message": "required key [adminSslPort] not found"
},
{
"schemaLocation": "#/definitions/weblogic/properties/type",
"pointerToViolation": "#/middleware/1/type",
"causingExceptions": [],
"keyword": "const",
"message": ""
}
],
"message": "2 schema violations found"
},
{
"schemaLocation": "#/definitions/tomcat/properties/buildInfo",
"pointerToViolation": "#/middleware/1/buildInfo",
"causingExceptions": [],
"keyword": "required",
"message": "required key [classpath] not found"
}
],
"keyword": "oneOf",
"message": "#: 0 subschemas matched instead of one"
}
]
Is there a way to only validate against the subschema that the type matches against?
You can use if and then keywords as follows.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "#",
"type": "object",
"title": "The Root Schema",
"required": [
"middleware"
],
"properties": {
"middleware": {
"$ref": "#/definitions/middleware"
}
},
"definitions": {
"middleware":{
"type": "array",
"items": {
"type": "object",
"allOf": [
{"$ref": "#/definitions/weblogic"},
{"$ref": "#/definitions/tomcat"}
],
"required": ["type","buildInfo"]
}
},
"weblogic": {
"if": {
"properties": {
"type": {
"const": "weblogic"
}
}
},
"then": {
"properties": {
"buildInfo": {
"properties": {
"adminSslPort": {
"type": "integer"
}
},
"additionalProperties": false,
"required": ["adminSslPort"]
}
}
}
},
"tomcat":{
"if": {
"properties": {
"type": {
"const": "tomcat"
}
}
},
"then": {
"properties": {
"buildInfo":{
"properties": {
"classpath": {
"type": "string"
}
},
"additionalProperties": false,
"required": ["classpath"]
}
}
}
}
}
}

jsonschema Draft 0.7 required properties in nested object depending on a value

I have a json file with nested objects.
{
"apiVersion":"0.0.9b",
"apiDate":"18.01.19",
"general":{
"documentType": "invoice",
"references":{
"invoiceId":"123",
"invoiceDate":"01.01.1970",
"creditNoteId":"123",
"creditNoteDate":"01.01.1970"
}
}
}
Now I would like to define that invoiceId and invoiceDate should be required if documentType is invoice, and also the other way arraound (creditNoteId and Date are required if documentType is creditNote).
All other Properties should be optional.
Pseudo-Code:
documentType = invoice
- required: invoiceId, invoiceDate
- optional: creditNoteId, creditNoteDate
documentType = creditNote
- required: creditNoteId, creditNoteDate
- optional: invoiceId, invoiceDate
If i store all properties in the same object I found this working solution:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers"
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
},
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
},
"oneOf": [
{
"$comment": "Invoice",
"properties": {
"documentType": { "enum": ["invoice"] }
},
"required": ["invoiceId", "invoiceDate"]
},
{
"$comment": "CreditNote",
"properties": {
"documentType": { "enum": ["creditNote"] }
},
"required": ["creditNoteId", "creditNoteDate"]
}
]
}
}
}
Is there a way to display this dependency with nested objects used in the above json?
What I tried already was:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers"
},
"references": {
"type": "object",
"properties": {
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
},
"oneOf": [
{
"$comment": "Invoice",
"properties": {
"documentType": { "enum": ["invoice"] }
},
"required": ["invoiceId", "invoiceDate"]
},
{
"$comment": "CreditNote",
"properties": {
"documentType": { "enum": ["creditNote"] }
},
"required": ["creditNoteId", "creditNoteDate"]
}
]
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
}
}
}
}
}
But with this i get an Error from https://www.jsonschemavalidator.net
Message: JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: 0, 1.
What have I missed?
You're very close. You just need to pull your oneOf up to the top level so you can reference #/properties/general and #/properties/references from the same schema.
Also, you almost always want to use anyOf instead of oneOf. oneOf enforces that one and only one schema in the list validates. When the schemas are mutually exclusive, oneOf is just asking the validator to do unnecessary work.
"anyOf": [
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["invoice"] }
}
},
"references": {
"required": ["invoiceId", "invoiceDate"]
}
}
},
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["creditNote"] }
}
},
"references": {
"required": ["creditNoteId", "creditNoteDate"]
}
}
}
]
With the help of Jason Desrosiers I finaly found a solution also for my nested json.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"apiVersion",
"apiDate"
],
"anyOf": [
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["invoice"] },
"references": {
"required": ["invoiceId", "invoiceDate"]
}
}
}
}
},
{
"properties": {
"general": {
"properties": {
"documentType": { "enum": ["creditNote"] },
"references": {
"required": ["creditNoteId", "creditNoteDate"]
}
}
}
}
}
],
"properties": {
"apiVersion": {
"type": "string",
"description": "The version of the json file"
},
"apiDate": {
"type": "string",
"description": "The date when the json version was published"
},
"general": {
"$ref": "#/definitions/general_identifiers",
"references": {
"type": "object",
"properties": {
"invoiceId": {
"type": "string"
},
"invoiceDate": {
"type": "string"
},
"creditNoteId": {
"type": "string"
},
"creditNoteDate": {
"type": "string"
}
}
}
}
},
"definitions" : {
"general_identifiers" : {
"type": "object",
"required": [
"documentType"
],
"properties": {
"documentType": {
"enum": [
"invoice",
"creditNote"
]
}
}
}
}
}

why doesn't json schema validate definitions defined in required attribute

I'm trying to create a json schema that validates an object depending on its type. It picks the right definition, however, it doesn't validate the required attributes in the selected definition. Here is the json schema i am trying:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"literal": {
"type": "object",
"properties": {
"raw": { "type": "string" }
},
"required": ["raw"],
"additionalProperties": false
},
"identifier": {
"type": "object",
"properties": {
"name": { "type": "string" }
},
"required": ["name"],
"additionalProperties": false
}
},
"type": "object",
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"enum": ["Literal"]
},
"content": { "$ref": "#/definitions/literal" }
}
},
{
"type": "object",
"properties": {
"type": {
"enum": ["Identifier"]
},
"content": { "$ref": "#/definitions/identifier" }
}
}
],
"required": ["type"]
};
the following schema is valid, even tho its missing the "raw" property:
{ "type" : "Literal" }
thanks
There is no keyword content in JSON Schema spec.
Once you have asserted "type":"object" in root schema, there is no need to do it again in subschema.
In order to combine object type enumerated value with associated extended definition, you need allOf keyword.
Also in definitions if you use "additionalProperties": false you have to list all properties of the object (see "type": {}). For previously defined/validated properties you can just use permissive schema: {} or true.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"literal": {
"properties": {
"type": {},
"raw": { "type": "string" }
},
"required": ["raw"],
"additionalProperties": false
},
"identifier": {
"properties": {
"type": {},
"name": { "type": "string" }
},
"required": ["name"],
"additionalProperties": false
}
},
"type": "object",
"oneOf": [
{
"allOf": [
{
"properties": {
"type": {
"enum": ["Literal"]
}
}
},
{"$ref": "#/definitions/literal"}
]
},
{
"allOf": [
{
"properties": {
"type": {
"enum": ["Identifier"]
}
}
},
{"$ref": "#/definitions/identifier" }
]
}
],
"required": ["type"]
}

Json schema auto completion property

I have already created my own schema on intellij environment, and it's working good, but still have problems in auto completion which provides intellij to the schema,
for example if object "car" defined in json schema then intellij can recognize that there's such object in the schema and intellij will give it as suggestion through out coding json, the problem that I'm facing is that the suggestions are contains all the objects that defined in the schema, but the expectations are to get the objects which defined under the scoop of another object
This is some code of my own schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Pipe File",
"type": "object",
"definitions": {
"Pipe": {
"type": "object",
"properties": {
"components": {
"$ref": "#/definitions/components"
}
},
"required": [
"components"
]
},
"components": {
"description": "section which defines the pipes in the file",
"type": "array",
"minItems": 1,
"items": {
"oneOf": [
{
"$ref": "#/definitions/setValuesComponent"
},
{
"$ref": "#/definitions/invokeWebServicesComp"
}
]
}
},
"setValuesComponent": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"type": {
"enum": [
"setValuesComp"
]
},
"out": {
"type": "object",
"properties": {
"dateFormat": {
"$ref": "#/definitions/setValuesCompOut"
},
"dateTimeFormat": {
"$ref": "#/definitions/setValuesCompOut"
},
"dateFormatBank": {
"$ref": "#/definitions/setValuesCompOut"
}
}
},
"condition": {
}
},
"required": [
"name",
"type",
"out"
]
},
"setValuesCompOut": {
"type": "object",
"properties": {
"exprValue": {
"type": "string"
},
"ctxEntry": {
"type": "string"
},
"value": {
"type": "string"
},
"exprConst": {
"type": "string",
"pattern": "(Class|class)\\.\\w+\\.\\w+"
}
},
"anyOf": [
{
"required": [
"exprValue"
]
},
{
"required": [
"ctxEntry"
]
},
{
"required": [
"value"
]
},
{
"required": [
"exprConst"
]
}
]
},
"invokeWebServicesComp": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"type": {
"enum": [
"invokeWebServices"
]
},
"mode": {
"enum": [
"innerJoin",
"leftJoin",
"union",
"parallelJoin"
]
},
"method": {
"type": "string"
},
"headers": {
"$ref": "#/definitions/invokeWebServicesCompHeaders"
},
"dataFilePath": {
"type": "string"
},
"restRelativeUrl": {
"type": "string"
},
"in": {
"$ref": "#/definitions/invokeWebServicesCompIn"
},
"out": {
"$ref": "#/definitions/invokeWebServicesCompOut"
}
},
"required": [
"type",
"name",
"out",
"in"
]
},
"invokeWebServicesCompOut": {
"type": "object",
"patternProperties": {
"doc": {
"type": "string",
"pattern": ".+"
}
}
},
"invokeWebServicesCompHeaders": {
"type": "object",
"patternProperties": {
".{1,}": {
"type": "string",
"pattern": ".+"
}
}
},
"invokeWebServicesCompIn": {
"type": "object",
"patternProperties": {
".{1,}": {
"type": "string",
"pattern": ".+"
}
}
},
"properties": {
"pipes": {
"description": "section which defines the mandatory pipes object in the file",
"type": "object",
"patternProperties": {
".{1,}": {
"$ref": "#/definitions/Pipe"
}
}
}
},
"required": [
"pipes"
]
}
}
So what I expected is, when the type of object determined to "setValuesComp", the auto completion will suggest the relevant properties, that's mean it will not suggest "in" property which is belong to "invokeWebServicesComp" not "setValuesComponent".this picture show the auto complete problem in my real environment
Your JSON schema seems to be invalid. The below JSON content should be present inside object type.
"properties": {
"pipes": {
"description": "section which defines the mandatory pipes object in the file",
"type": "object",
"patternProperties": {
".{1,}": {
"$ref": "#/definitions/Pipe"
}
}
}
},
"required": [
"pipes"
]
In your schema, it is present as part of the "definitions". Please make this correction and then check if you are able to get the suggestions.

Ensure one property is not empty in JSON schema

For the given schema below, is it possible to ensure that at least one property contains a value (ie, minLength is 1):
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"fundRaiseId": {
"type": "string"
},
"productTypeId": {
"type": "string"
},
"businessLineId": {
"type": "string"
}
}
}
So this would pass validation:
{
"fundRaiseId": "x"
}
And this would fail as no values are present:
{
"fundRaiseId": "",
"productTypeId": "",
"businessLineId": ""
}
I would try something like
{
"allOf": [{
"type": "object",
"properties": {
"fundRaiseId": {
"type": "string"
},
"productTypeId": {
"type": "string"
},
"businessLineId": {
"type": "string"
}
}
}, {
"anyOf": [{
"properties": {
"fundRaiseId": {
"$ref": "#/definitions/nonEmptyString"
}
}
}, {
"properties": {
"productTypeId": {
"$ref": "#/definitions/nonEmptyString"
}
}
}, {
"properties": {
"businessLineId": {
"$ref": "#/definitions/nonEmptyString"
}
}
}]
}],
"definitions": {
"nonEmptyString": {
"type": "string",
"minLength": 1
}
}
}
Explanation: the JSON to be validated should conform to 2 root-level schemas, one is your original definition (3 string properties). The other one contains 3 additional sub-schemas, each defining one of your original properties as non-empty string. These are wrapped in an "anyOf" schema, so at least one of these should match, plus the original schema.
Is it a requirement that you allow the values to be empty? You can write a much cleaner schema if you requiring that all the strings are non-empty.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"fundRaiseId": { "$ref": "#/definitions/non-empty-string" },
"productTypeId": { "$ref": "#/definitions/non-empty-string" },
"businessLineId": { "$ref": "#/definitions/non-empty-string" }
},
"anyOf": [
{ "required": ["fundRaiseId"] },
{ "required": ["productTypeId"] },
{ "required": ["businessLineId"] }
],
"definitions": {
"non-empty-string": {
"type": "string",
"minLength": 1
},
}
}