Array of objects or strings in JSON Schema - json

struggling to find a definitive answer to this.
I'd writing some JSON schema validation, and wish to validate against the incoming payload being either an array of strings (that match a pattern) or an array of objects.
For instance...
{
"src" : [
{
"serviceName" : "svc1",
"filename" : "ABC000000001234567.tar"
},
{
"serviceName" : "svc2",
"filename" : "DEF000000001234567.tar"
}
]
}
..or...
{
"src" : [
"file://svc1/ABC000000001234567.tar",
"file://svc2/DEF000000001234567.tar"
]
}
I have this at the moment, but it isn't working...
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"title": "My schema",
"additionalProperties": false,
"properties": {
"src": {
"type": "array",
"additionalItems": false,
"items": {
"oneOf": [
{
"$ref": "#/definitions/svcUrl"
},
{
"$ref": "#/definitions/svcObj"
}
]
}
}
},
"definitions": {
"svcUrl": {
"type": "string",
"pattern": "^file\\:\\/\\/",
"required": []
},
"svcObj": {
"type": "object",
"properties": {
"serviceName": {
"type": "string"
},
"filename": {
"type": "string"
}
},
"required": [
"RequiredProperty",
"filename",
"serviceName"
]
}
}
}
Can anyone help shed some light on this for me please?

Related

JSON Schema Grammar Not Validating Enums

I have defined the following JSON Schema Grammar which has to take "TypeA" type of elements and none other than that.
{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Schema definition",
"type": "object",
"scname": "string",
"properties": {
"itemInfo": {
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/definitions/TypeADefinition"
}
]
}
}
},
"required": [
"itemInfo"
],
"definitions": {
"TypeADefinition": {
"type": "object",
"properties": {
"elementOf": {
"types": {
"enum": [
"TypeA"
]
}
},
"elements": {
"items": {
"oneOf": [
{
"$ref": "#/definitions/TypeAElementDefinition"
}
]
},
"type": "array"
}
}
},
"TypeAElementDefinition": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 128
}
},
"required": [
"name"
],
"additionalProperties": false
}
}
}
JSON Object 1:
{
"itemInfo": [
{
"elementOf": "TypeA",
"elements": [
{
"name": "John Doe"
}
]
}
]
}
JSON Object 2:
{
"itemInfo": [
{
"elementOf": "TypeB",
"elements": [
{
"name": "John Doe"
}
]
}
]
}
Both of these JSON objects are getting validated by the JSON grammar that I have defined but only the first JSON object should be validated successfully by the grammar the second JSON should not validated as it has elementOf "TypeB".
Is there anything that is missing in my Schema Grammar?
UPDATE
After updating the schema grammar to the following, I am able to invalidate 2nd JSON object.
{
"$schema": "http://json-schema.org/draft-04/schema",
"title": "Schema definition",
"type": "object",
"scname": "string",
"properties": {
"itemInfo": {
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/definitions/TypeADefinition"
},
{
"$ref": "#/definitions/TypeBDefinition"
}
]
}
}
},
"required": [
"itemInfo"
],
"definitions": {
"TypeADefinition": {
"type": "object",
"properties": {
"elementOf": {
"type": "string",
"enum": [
"TypeA"
]
},
"elements": {
"items": {
"oneOf": [
{
"$ref": "#/definitions/TypeAElementDefinition"
}
]
},
"type": "array"
}
}
},
"TypeAElementDefinition": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 128
}
},
"required": [
"name"
],
"additionalProperties": false
},
"TypeBDefinition": {
"type": "object",
"properties": {
"elementOf": {
"type": "string",
"enum": [
"TypeB"
]
},
"elements": {
"items": {
"oneOf": [
{
"$ref": "#/definitions/TypeBElementDefinition"
}
]
},
"type": "array"
}
}
},
"TypeBElementDefinition": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 128
}
},
"required": [
"name"
],
"additionalProperties": false
}
}
}
I have also added a definition for 'TypeB' in the grammar which should validate TypeB elements. But it is not happening.
TypeB element is referring to 'TypeADefinition', which should not happen. What is the issue with the grammar?
Error:
Message: Value "TypeB" is not defined in enum.
Schema path: #/definitions/TypeADefinition/properties/elementOf/enum

Json schema validation for object which may have two forms

I'm trying to figure out how to validate a JSON object which may have 2 forms.
for examples
when there is no data available, the JSON could be
{
"student": {}
}
when there is data available, the JSON could be
{
"student":{
"id":"someid",
"name":"some name",
"age":15
}
}
I wrote the JSON schema in this way, but it seems not working
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://json-schema.org/draft-07/schema#",
"title": "JSON schema validation",
"properties": {
"student": {
"type": "object",
"oneOf": [
{
"required": [],
"properties": {}
},
{
"required": [
"id",
"name",
"age"
],
"properties": {
"id": {
"$id": "#/properties/student/id",
"type": [
"string",
"null"
]
},
"name": {
"$id": "#/properties/student/name",
"type": [
"string",
"null"
]
},
"age": {
"$id": "#/properties/student/age",
"type": [
"number"
]
}
}
}
]
}
}
}
I was wondering is there a way to validate it. Thank you!
An empty properties object, and an empty required object, do nothing.
JSON Schema is constraints based, in that if you don't explicitly constrain what is allowed, then it is allowed by default.
You're close, but not quite. The const keyword can take any value, and is what you want in your first item of allOf.
You can test the following schema here: https://jsonschema.dev/s/Kz1C0
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://example.com/myawesomeschema",
"title": "JSON schema validation",
"properties": {
"student": {
"type": "object",
"oneOf": [
{
"const": {}
},
{
"required": [
"id",
"name",
"age"
],
"properties": {
"id": {
"type": [
"string",
"null"
]
},
"name": {
"type": [
"string",
"null"
]
},
"age": {
"type": [
"number"
]
}
}
}
]
}
}
}

JSON is not getting validated based on schema

I must be missing something here, but the below JSON is not getting validated against the schema.
For example, the required attribute from the Java/JavaScript object is never getting enforced as per the schema. (FYI- Every language object may have other attributes or nested object)
However, if I completely remove the definition and directly put under array items each separately, then it validates.
I want to use 'definitions' and gets validated.The reason I have to put all the object in definitions and later I may have to put different language object in oneOf/allOf for other certain validation check.
Online check:
Schema and JSON
JSON
{
"languages": [
{
"lang": "Java",
"trainer": "Peter"
},
{
"lang": "JavaScript",
"enrolled": "42",
"available": "5"
}
]
}
and the Schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"languages"
],
"properties": {
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object"
},
"anyOf": [
{
"$ref": "#/definitions/Java"
},
{
"$ref": "#/definitions/JavaScript"
}
]
}
},
"definitions": {
"Java": {
"required": [
"trainer"
],
"properties": {
"lang": {
"enum": [
"Java"
]
},
"trainer": {
"type": "string"
}
}
},
"JavaScript": {
"required": [
"enrolled",
"available"
],
"properties": {
"lang": {
"enum": [
"JavaScript"
]
},
"enrolled": {
"type": "string"
},
"available": {
"type": "string"
}
}
}
}
}
The fixed schema and it works now
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"required": [
"languages"
],
"properties": {
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{
"$ref": "#/definitions/Java"
},
{
"$ref": "#/definitions/JavaScript"
}
]
}
}
},
"definitions": {
"Java": {
"required": [
"trainer"
],
"properties": {
"lang": {
"enum": [
"Java"
]
},
"trainer": {
"type": "string"
}
}
},
"JavaScript": {
"required": [
"enrolled",
"available"
],
"properties": {
"lang": {
"enum": [
"JavaScript"
]
},
"enrolled": {
"type": "string"
},
"available": {
"type": "string"
}
}
}
}
}
I think that the "array" definition is not correct. The objects that can be added in the array must be refereed in the "items", after you define the type of the items. Something like this:
"languages": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"anyOf": [
{"$ref": "#/definitions/Java"},
{"$ref": "#/definitions/JavaScript"}
]
}
}
I have fixed myself
What I did: I have placed the json object blocks under items section of array.

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.

AJV schema validation error

I have the input json like below,
{"contents":[{"type":"field"},{"type":"field","itemId":"594b9980e52b5b0768afc4e8"}]}
the condition is,
if the type is 'field', then 'itemId' should be the required field
and if the type is 'fieldGroup' or 'subSection', then 'itemId' is optional
This is the Json Schema I tried and its not working as expected,
"type": "object",
"additionalProperties": false,
"properties" : {
"contents" : {
"type" : "array",
"items": {"$ref": "#displayItem" }
}
},
"definitions": {
"displayItem" : {
"id": "#displayItem",
"type": "object",
"items": {
"anyOf": [
{"$ref": "#fieldType"},
{"$ref": "#fieldGroupSubSectionType"}
]
}
},
"fieldType" : {
"id": "#fieldType",
"type": "object",
"additionalProperties": false,
"properties": {
"itemId": {
"type": "string"
},
"type": {
"type": "string",
"enum": ["field"]
}
}
},
"fieldGroupSubSectionType" : {
"id": "#fieldGroupSubSectionType",
"type": "object",
"additionalProperties": false,
"properties": {
"itemId": {
"type": [ "string", "null" ]
},
"type": {
"type": "string",
"enum": [
"fieldGroup",
"subSection"
]
}
}
}
}
Any help / workaround with Sample Json Schema to achieve the above use case is appreciated.
If I understand the description of what you want correctly, then the json example you provide is not valid since it has a type: "field" but does not have an "itemId" property.
Assuming that is true. Instead of using
type: ["string", null]
use the required property.
I changed your schema a bit, instead of having separate definitions I inlined them, but other than that (and the use of required) is the same:
{
"type": "object",
"additionalProperties": false,
"properties": {
"contents": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"itemId": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"field"
]
}
},
"required": [
"itemId"
]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"itemId": {
"type": "string"
},
"type": {
"type": "string",
"enum": [
"fieldGroup",
"subSection"
]
}
}
}
]
}
}
}
}
Here is your answer with a little cleanup for best practices and style. The trick is that you need to use implication "a implies b <=> (not a) or b". In this case you have "type = field implies itemId is required <=> type is not field or itemId is required".
{
"type": "object",
"properties": {
"contents": {
"type": "array",
"items": { "$ref": "#/definitions/displayItem" }
}
},
"definitions": {
"displayItem": {
"type": "object",
"properties": {
"itemId": { "type": "string" },
"type": { "enum": ["field", "fieldGroup", "subSection"] }
},
"anyOf": [
{ "not": { "$ref": "#/definitions/fieldType" } },
{ "required": ["itemId"] }
]
},
"fieldType": {
"properties": {
"type": { "enum": ["field"] }
}
}
}
}