I have created a JSON schema following the draft v3 specifications. The schema looks like this:
{
"housePolicies": {
"properties": {
"guaranteePolicies": {
"items": {
"$ref": "#/housePolicies/guaranteePolicy"
},
"type": "array"
},
"specialRequirements": {
"items": {
"$ref": "#/housePolicies/specialRequirement"
},
"type": "array"
},
"chainCode": {
"required": true,
"type": "string",
"description": "Unique identifier of the chain"
},
"losRestrictions": {
"items": {
"$ref": "#/housePolicies/losRestriction"
},
"type": "array"
},
"specialEvents": {
"items": {
"$ref": "#/housePolicies/specialEvent"
},
"type": "array"
},
"propertyCode": {
"required": true,
"type": "string",
"description": "Unique identifier of the property in the chain"
}
},
"specialRequirement": {
"id": "specialRequirement",
"properties": {
"minLOS": {
"type": "integer",
"description": "Minimum stay, in days, that applies for a special requirement restriction.\nOptional: If no input provided, there is no minimum LOS required for that period.",
"format": "int64"
},
"startDate": {
"required": true,
"type": "string",
"description": "Date when a special requirement restriction starts",
"format": "date"
},
"endDate": {
"required": true,
"type": "string",
"description": "Date when a special requirement restriction ends",
"format": "date"
}
}
},
"guaranteePolicy": {
"dow": {
"id": "dow",
"properties": {
"monday": {
"required": true,
"type": "boolean"
},
"tuesday": {
"required": true,
"type": "boolean"
},
"friday": {
"required": true,
"type": "boolean"
},
"wednesday": {
"required": true,
"type": "boolean"
},
"thursday": {
"required": true,
"type": "boolean"
},
"sunday": {
"required": true,
"type": "boolean"
},
"saturday": {
"required": true,
"type": "boolean"
}
}
},
"id": "guaranteePolicy",
"properties": {
"startDate": {
"required": true,
"type": "string",
"description": "Date when a guarantee policy starts",
"format": "date"
},
"endDate": {
"required": true,
"type": "string",
"description": "Date when a guarantee policy ends",
"format": "date"
},
"guaranteeRequiredDow": {
"items": {
"$ref": "#/housePolicies/guaranteePolicy/dow"
},
"required": true
}
}
},
"losRestriction": {
"id": "losRestriction",
"properties": {
"startDate": {
"required": true,
"type": "string",
"description": "Date when a length of stay restriction starts",
"format": "date"
},
"max": {
"type": "integer",
"description": "In case max is not provided it measn that there is no maximum length of stay restrictions.\nOptional: If no input provided, there is no maximum length restriction.",
"format": "int64"
},
"endDate": {
"required": true,
"type": "string",
"description": "Date when a length of stay restriction ends",
"format": "date"
},
"min": {
"type": "integer",
"description": "In case min is not provided it means that there is no minimum length of stay restrictions.\nOptional: If no input provided, there is no minimum length restriction.",
"format": "int64"
}
}
},
"specialEvent": {
"id": "specialEvent",
"properties": {
"startDate": {
"required": true,
"type": "string",
"description": "Date when a special event restriction starts",
"format": "date"
},
"endDate": {
"required": true,
"type": "string",
"description": "Date when a special event restriction ends",
"format": "date"
}
}
},
"id": "housePolicies"
},
"$schema": "http://json-schema.org/draft-03/schema#",
"id": "request",
"properties": {
"housePolicies": {
"items": {
"$ref": "#/housePolicies"
},
"required": true
}
}
}
I am now trying to validate some JSON against it, but jsonschemavalidator complains about the schema, giving error when resolving schema reference '#/housePolicies/guaranteePolicy/dow'. I verified in the documentation that the references are put in the proper format. Could anyone point where is the error in this schema?
You have used json-path in your $ref, but still use an id on the objects. You don't need both and they seem to be conflicting. If you remove the id's, your schema works.
Related
Is it possible to make a field required/non-required depending on other field value in JSON schema?
JSON schema contains mode field. If it equals to 'release' or 'debug', the file_path is not required. If it equals to 'custom' it is required.
"mode": {
"enum": [
"debug",
"release",
"custom"
],
"id": "mode",
"required": true,
"type": "string"
},
"file_path": {
"id": "file_path",
"required": false,
"type": "string"
}
There is a solution for JSON Schema draft 7:
{
"build": {
"type": "object",
"id": "build",
"oneOf": [
{
"$ref": "#/definitions/ReleaseDebug"
},
{
"$ref": "#/definitions/Custom"
}
]
}
},
"definitions": {
"ReleaseDebug": {
"required": ["mode"],
"properties": {
"mode": {
"type": "string",
"enum": [
"debug",
"release"
],
"id": "mode"
}
}
},
"Custom": {
"required": ["mode", "file_path"],
"properties": {
"mode": {
"type": "string",
"enum": [
"custom"
],
"id": "mode"
},
"file_path": {
"type": "string",
"id": "file_path"
},
}
}
}
Using Draft-07
What I got was
valid JSON
What error I expected from audit object was
directory: String length must be greater than or equal to 2
Tried two different validators with same results
https://www.jsonschemavalidator.net/
GoLang https://github.com/xeipuuv/gojsonschema
This is my schema
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ISAM-Wrapper",
"description": "Validate isam wrapper json",
"type": "object",
"properties": {
"directory": {
"description": "path to location of isam file",
"type": "string",
"minLength": 2
},
"isamFile": {
"description": "isam database file",
"type": "string",
"minLength": 4
},
"isamIndex": {
"description": "isam index file",
"type": "string",
"minLength": 4
},
"port": {
"description": "port number for REST listener",
"type": "integer",
"minimum": 60410,
"maximum": 69999
},
"actions": {
"description": "Which operations are supported",
"type": "object",
"items": {
"properties": {
"create": {
"type": "boolean"
},
"read": {
"type": "boolean"
},
"update": {
"type": "boolean"
},
"delete": {
"type": "boolean"
}
}
},
"required": [
"create",
"read",
"update",
"delete"
]
},
"fields": {
"description": "each object describes one field of the isam file",
"type": "array",
"minItems": 1,
"items": {
"title": "field",
"description": "field schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"ordinal": {
"type": "integer",
"minimum": 0
},
"offset": {
"type": "integer",
"minimum": 0
},
"length": {
"type": "integer",
"minimum": 1
},
"dataType": {
"enum": [
"uchar",
"ulong",
"long",
"uint",
"int",
"ushort",
"short"
]
}
},
"required": [
"name",
"ordinal",
"offset",
"length",
"dataType"
]
}
},
"audit": {
"description": "input needed to enable and configure isam auditing",
"type": "object",
"items": {
"properties": {
"enable": {
"enum": [
true,
false
]
},
"directory": {
"type": "string",
"minLength": 2
},
"fileName": {
"type": "string",
"minLength": 4
},
"workDirectory": {
"type": "string",
"minLength": 2
},
"archiveDirectory": {
"type": "string",
"minLength": 2
},
"interval": {
"type": "integer",
"minimum": 1
},
"byteThreshold": {
"type": "integer",
"minimum": 1048576,
"maximum": 1073741824
}
}
},
"required": [
"enable"
],
"if": {
"not": {
"properties": {
"enable": {
"enum": [
false
]
}
}
}
},
"then": {
"required": [
"directory",
"fileName",
"workDirectory",
"archiveDirectory",
"interval",
"byteThreshold"
]
}
}
},
"required": [
"directory",
"isamFile",
"isamIndex",
"port",
"actions",
"fields",
"audit"
]
}
This is my JSON
{
"directory": "./",
"isamFile": "isam.dat",
"isamIndex": "isam.idx",
"port": 60410,
"actions": {
"create": true,
"read": true,
"update": true,
"delete": true
},
"fields": [
{
"name": "F1",
"ordinal": 0,
"offset": 0,
"length": 4,
"dataType": "ulong"
},
{
"name": "F2",
"ordinal": 1,
"offset": 4,
"length": 4,
"dataType": "ulong"
}
],
"audit": {
"enable": true,
"directory": "",
"fileName": "file",
"workDirectory": "./work",
"archiveDirectory": "./archive",
"interval": 5,
"byteThreshold": 1500000
}
}
This issue you have is that your schema is invalid. For both actions and audit you specify these as objects but you don't provide any properties. What you do do, however, is specify an items key (which does nothing here - that's a key on an array) which contains the properties.
Once you correct this error, the schema behaves as you intend, see https://repl.it/repls/BlankWellmadeFrontpage
I have the following json-schema which defines 3 types of toys, to be used with this json GUI builder (github):
{
"id": "http://some.site.somewhere/entry-schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "schema for toys in game",
"type": "object",
"required": [ "type" ],
"properties": {
"sawObj": {
"type": "object",
"oneOf": [
{ "$ref": "#/definitions/rect" },
{ "$ref": "#/definitions/circle" },
{ "$ref": "#/definitions/img" }
]
}
},
"definitions": {
"rect": {
"properties": {
"width": { "type": "integer" },
"height": { "type": "integer" },
"weight": { "type": "integer" }
},
"required": [ "width", "height", "weight" ],
"additionalProperties": false
},
"circle": {
"properties": {
"radius": { "type": "integer" },
"weight": { "type": "integer" }
},
"required": [ "radius", "weight" ],
"additionalProperties": false
},
"img": {
"properties": {
"path": { "type": "string" },
"width": { "type": "integer" },
"height": { "type": "integer" },
"weight": { "type": "integer" }
},
"required": [ "path", "width", "height", "weight" ],
"additionalProperties": false
}
}
}
If I pick the circle object for example I get an output:
{
"sawObj": {
"radius": 0,
"weight": 0
}
}
I want to add a value "type" which would always be constrained to reflect the users chosen type. So instead something like this:
{
"sawObj": {
"type": "circle",
"radius": 0,
"weight": 0
}
}
Where the type is automatically determined by the users choice from the oneOf properties section.
How can I do this with json-schema?
I was able to do this the enum value and only allowing a single value representing the type. I also set the type value as required so it is always automatically set to 'circle'.
"circle": {
"properties": {
"radius": {
"type": "integer"
},
"weight": {
"type": "integer"
},
"type": {
"type": "string",
"enum": ["circle"]
}
},
"required": ["radius", "weight", "type"],
"additionalProperties": false
}
Note: I want to point out this solution is not ideal. I'm hoping to find a better way to do this.
I'm trying to build a json schema with "chained" definition.
For the given schema :
{
"$schema": "http://json-schema.org/schema#",
"id": "http://toto/filter-schema#",
"title": "filter schema definition",
"type": "object",
"description": "filter data",
"definitions": {
"timeFilters": {
"type": "object",
"oneOf": [
{
"properties": {
"since": {
"type": "string",
"format": "date-time",
"description": "sends only items that have been modified AFTER this"
}
},
"additionalProperties": false,
"required": [
"since"
]
},
{
"properties": {
"from": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date AFTER this"
},
"to": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date BEFORE this"
}
},
"additionalProperties": false,
"required": [
"from",
"to"
]
}
]
},
"objectFilters": {
"type": "object",
"properties": {
"objectFilters": {
"type": "array",
"description": "the array of object filter",
"minItems": 1,
"uniqueItems": true,
"items": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"targetClass": {
"type": "string",
"description": "the target class"
},
"targetAttribute": {
"type": "string",
"description": "the target attribute"
},
"test": {
"type": "string",
"description": "the test on the attribute value"
}
}
}
]
}
},
"additionalProperties": false
}
},
"anyOf": [
{
"additionalProperties": false
},
{
"$ref": "#/definitions/timeFilters",
"additionalProperties": false
},
{
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
]
}
this schema is validating
{
"since": "2016-02-17T01:02:03.1Z"
}
and
{
"from": "2016-02-17T01:02:03.1Z",
"to": "2016-02-17T01:02:03.1Z",
}
and
{
"objectFilters": [
{
"targetClass": "test",
"targetAttribute": "test",
"test": "test"
}
]
}
and even
{}
but not
{
"since": "2016-02-17T01:02:03.1Z",
"objectFilters": [
{
"targetClass": "test",
"targetAttribute": "test",
"test": "test"
}
]
}
How can make it validating the last json ?
I have tried to add a new definition to the "anyOf", something like this :
{
"$ref": "#/definitions/timeFilters",
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
but it does not work.
I use the draft v4.
EDIT :
Also tried
{
"$ref": "#/definitions/timeFilters",
"additionalProperties": {
"$ref": "#/definitions/objectFilters",
"additionalProperties": false
}
}
not working either
The behavior of additionalProperties can get confusing when combining schemas. I suggest a different approach. It's easier to declare all your properties upfront and then declare the required properties constraints separately.
The dependencies keyword works well in this case.
http://json-schema.org/latest/json-schema-validation.html#anchor70
{
"$schema": "http://json-schema.org/schema#",
"id": "http://toto/filter-schema#",
"title": "filter schema definition",
"description": "filter data",
"type": "object",
"properties": {
"since": {
"type": "string",
"format": "date-time",
"description": "sends only items that have been modified AFTER this"
},
"from": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date AFTER this"
},
"to": {
"type": "string",
"format": "date-time",
"description": "return only data that have a validity date BEFORE this"
},
"objectFilters": {
"type": "array",
"description": "the array of object filter",
"minItems": 1,
"uniqueItems": true,
"items": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"targetClass": {
"type": "string",
"description": "the target class"
},
"targetAttribute": {
"type": "string",
"description": "the target attribute"
},
"test": {
"type": "string",
"description": "the test on the attribute value"
}
}
}
]
}
},
"additionalProperties": false,
"dependencies": {
"since": {
"not": { "required": ["from"] }
},
"from": ["to"],
"to": ["from"]
}
}
I'm having trouble trying to create a schema that makes use of both oneOf and a common referenced sub-schema, in order to avoid having to duplicate parts of the schema.
The JSON that the schema should be validating against looks as follows:
{
"createdDate": "2015-01-20T17:10:05Z",
"createdBy": "testUser",
"lastModifiedDate": "2015-01-20T17:10:05Z",
"lastModifiedBy": "testUser",
"fileUrl": {
"path": "/path/to/file",
"fileName": "file.pdf"
},
"referenceType": "person",
"fileType": "certificate",
"personId": "12345"
}
From this, the common part is:
{
"createdDate": "2015-01-20T17:10:05Z",
"createdBy": "testUser",
"lastModifiedDate": "2015-01-20T17:10:05Z",
"lastModifiedBy": "testUser",
"fileUrl": {
"path": "/path/to/file",
"fileName": "file.pdf"
}
}
The remaining 3 fields are always the same in name and all required, but the allowed enum values for them will vary.
So the schema for the remaining 3 could be one of the following:
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"vehicle"
]
},
"fileType": {
"type": "string",
"enum": [
"registration document"
]
},
"vehicleId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"vehicleId"
]
}
OR
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"person"
]
},
"fileType": {
"type": "string",
"enum": [
"certificate"
]
},
"personId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"personId"
]
}
I can't seem to create a schema whereby I can avoid duplicating the common fields, and have the oneOf, and set additionalProperties to false across the whole schema.
With the below example, trying to set additionalProperties to false causes validation errors. Is it possible to do what I'm trying to do?
{
"type": "object",
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"commonFile": {
"properties": {
"createdDate": {
"type": "string",
"format": "date-time"
},
"createdBy": {
"type": "string",
"pattern": "[^ ]"
},
"lastModifiedDate": {
"type": "string",
"format": "date-time"
},
"lastModifiedBy": {
"type": "string",
"pattern": "[^ ]"
},
"fileUrl": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": {
"type": "string",
"pattern": "[^ ]"
},
"fileName": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"path",
"fileName"
]
}
}
}
},
"oneOf": [{
"allOf": [
{"$ref": "#/definitions/commonFile"},
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"person"
]
},
"fileType": {
"type": "string",
"enum": [
"certificate"
]
},
"personId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"personId"
]
}
]
}, {
"allOf": [
{"$ref": "#/definitions/commonFile"},
{
"properties": {
"referenceType": {
"type": "string",
"enum": [
"vehicle"
]
},
"fileType": {
"type": "string",
"enum": [
"registration document"
]
},
"vehicleId": {
"type": "string",
"pattern": "[^ ]"
}
},
"required": [
"vehicleId"
]
}
]
}
],
"required": [
"createdDate",
"createdBy",
"lastModifiedDate",
"lastModifiedBy",
"fileUrl",
"referenceType",
"fileType"
]
}
I recommend not setting additionalProperties to false. It is usually best just to quietly ignore properties that are not defined. The following schema is what you would have to do to accomplish your goal.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"createdDate": { "type": "string", "format": "date-time" },
"createdBy": { "type": "string", "pattern": "[^ ]" },
"lastModifiedDate": { "type": "string", "format": "date-time" },
"lastModifiedBy": { "type": "string", "pattern": "[^ ]" },
"fileUrl": {
"type": "object",
"additionalProperties": false,
"properties": {
"path": { "type": "string", "pattern": "[^ ]" },
"fileName": { "type": "string", "pattern": "[^ ]" }
},
"required": ["path", "fileName"]
},
"referenceType": { "type": "string" },
"fileType": { "type": "string" },
"personId": {},
"vehicleId": {}
},
"additionalProperties": false,
"anyOf": [
{
"properties": {
"referenceType": { "enum": ["person"] },
"fileType": { "enum": ["certificate"] },
"personId": { "type": "string", "pattern": "[^ ]" }
},
"required": ["personId"],
"not" : { "required": ["vehicleId"] }
},
{
"properties": {
"referenceType": { "enum": ["vehicle"] },
"fileType": { "enum": ["registration document"] },
"vehicleId": { "type": "string", "pattern": "[^ ]" }
},
"required": ["vehicleId"],
"not" : { "required": ["personId"] }
}
],
"required": ["createdDate", "createdBy", "lastModifiedDate", "lastModifiedBy", "fileUrl", "referenceType", "fileType"]
}
The first thing I did was remove all the extraneous allOfs. Only one anyOf is needed. I defined the common properties in the main schema. The variations are described in the anyOf clause.
If you set additionalProperties to false, an additional schema (such as allOf, oneOf, and anyOf) can not introduce new properties. This means that all properties that are going to be allowed in this schema must be included in the schema that declares additionalProperties to be false. That is why I declared referenceType, fileType, personId, and vechicleId in the main schema.
The problem now is that additionalProperties no longer excludes vehicleId when referenceType is person or personId when referenceType is vehicle. To make sure this isn't allowed, I added the not clauses.
If were you add a third variation, restricting additional properties gets even more difficult. It's not just adding an additional referenceType to the anyof schema array. You also have to add new properties to the main schema and disallow those new types for all of the existing referenceTypes. You have to make changes all over the schema instead of just the area that is changing. This is why setting additionalProperties to false is generally not the best idea.