I have created a JSON schema to validate a simple JSON file. The good news is that it validates in the way that I intended, in that any number of booking elements can appear in any order, and no extra properties are allowed in each type of booking element.
Ideally I would like to remove the full list of possible properties in a bookingElement object (id, type, depair, destair, city) in the JSON schema, and just leave the oneOf lists, which show clearly which fields are allowed in each different type of element.
Can anyone provide a version of the schema without that full list that still applies the strict rules?
This is the JSON:
{
"bookingElements": [
{
"id" : "00003",
"type" : "flight",
"depair" : "LHR",
"destair" : "CDG"
},
{
"id" : "00008",
"type" : "hotel",
"city" : "Paris"
}
]
}
The schema is:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"bookingElements": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"depair": {
"type": "string"
},
"destair": {
"type": "string"
},
"city": {
"type": "string"
}
},
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"depair": {
"type": "string"
},
"destair": {
"type": "string"
}
}
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"city": {
"type": "string"
}
}
}
]
}
}
},
"required": [
"bookingElements"
]
}
Ideally the JSON schema would look something closer to the following:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"bookingElements": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"depair": {
"type": "string"
},
"destair": {
"type": "string"
}
}
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"type": {
"type": "string"
},
"city": {
"type": "string"
}
}
}
]
}
}
},
"required": [
"bookingElements"
]
}
Related
I have following JSON schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"Payload": {
"type": "object",
"additionalProperties": false,
"properties": {
"Person": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"Id": {
"type": "string"
},
"Name": {
"type": "string"
}
},
"required": [
"Id",
"Name"
]
}
}
}
},
"Reference": {
"type": "object",
"additionalProperties": false,
"properties": {
"Status": {
"anyOf": [
{
"Passed": {
"type": "string"
},
"Failed": {
"type": "string"
}
}
]
}
}
}
},
"anyOf": [
{
"additionalProperties": false,
"properties": {
"Status": {
"type": "string",
"enum": [
"Failed"
]
}
},
"required": [
"Reference"
],
"not": {
"required": [
"Payload"
]
}
},
{
"additionalProperties": true,
"properties": {
"Status": {
"type": "string",
"enum": [
"Passed"
]
}
},
"required": [
"Reference"
]
}
]
}
I want to check if JSON message has status failed then person array should not be present.
It should be present only if status is passed.
I tried following solution here but definitely i am doing something wrong as validator passes with Failed status and person details present. Can someone tell what I may be doing wrong?
You have a few issues.
/properties/Reference/properties/Status
This isn't a valid schema. It looks like you're trying to describe an enum.
additionalProperties
The reason is complicated, but the conditional patterns don't work with additionalProperties. The good news is it's also unnecessary. You can just leave those out.
/anyOf
Looks like you're using the "Enum" pattern, but the implication pattern is better in this case because only one of the enum states has additional constraints.
Conditional on nested property
Your schemas that define the Reference.Status value are actually just pointing to Status. You need a schema that describes the parent property as well.
The following does what I think your schema was trying to do.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"properties": {
"Payload": {
"type": "object",
"additionalProperties": false,
"properties": {
"Person": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"Id": { "type": "string" },
"Name": { "type": "string" }
},
"required": ["Id", "Name"]
}
}
}
},
"Reference": {
"type": "object",
"additionalProperties": false,
"properties": {
"Status": { "enum": ["Passed", "Failed"] }
}
}
},
"anyOf": [
{
"not": {
"properties": {
"Reference": {
"properties": {
"Status": { "enum": ["Failed"] }
},
"required": ["Status"]
}
},
"required": ["Reference"]
}
},
{ "not": { "required": ["Payload"] } }
]
}
As I am new to JSON schema creation, I have learnt the basics of JSON schema and now I am trying to create JSON schema for the below mentioned set of data,
{
"Result": [
{
"ResourceName": "Appointment",
"Sequence": "1",
"Data": {
"AppointmentID": "A1234",
"PatientName": "Test Patient",
"ClinicName": "Test Clinic"
}
},
{
"ResourceName": "EpisodeofCare",
"Sequence": "2",
"Data": {
"EpisodeID": "EP1234",
"LocationId": "L1234",
"AppointmentId": "A1234",
"TransactionStatus": "2",
"OPNumber": "OP523367"
}
},
{
"ResourceName": "Encounter",
"Sequence": "3",
"Data": {
"EncounterID": "E1234",
"PatientID": "P1234"
}
}
]
}
Can anybody please help me to create JSON schema for this kind of data set.
Thanks in advance for helping me out on this.
Below is the JSON schema i have drafted
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ResultType": {
"type": "object",
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string"
},
"Data": {
"type": "object",
"anyOf": [
{
"$ref": "#/definitions/Appointment"
},
{
"$ref": "#/definitions/EpisodeofCare"
},
{
"$ref": "#/definitions/Encounter"
}
]
}
}
},
"Appointment": {
"type": "object",
"properties": {
"AppointmentID": {
"type": "boolean"
},
"PatientName": {
"type": "string"
},
"ClinicName": {
"type": "string"
}
}
},
"EpisodeofCare": {
"type": "object",
"properties": {
"EpisodeID": {
"type": "string"
},
"LocationId": {
"type": "string"
},
"AppointmentId": {
"type": "string"
},
"TransactionStatus": {
"type": "string"
},
"OPNumber": {
"type": "string"
}
}
},
"Encounter": {
"type": "object",
"properties": {
"EncounterID": {
"type": "string"
},
"PatientID": {
"type": "string"
}
}
}
},
"type": "object",
"properties": {
"Result": {
"type": "array",
"$ref": "#/definitions/ResultType"
}
}
}
Throw it in a schema validator like this one.
You will see errors in your schemas definition and in validation.
First of all check that your schema is valid json (the validator might help):
[
{
{"$ref": "#/definitions/Appointment"} <- unnecessary and invalid braces
},
{
{"$ref": "#/definitions/EpisodeofCare"} <- unnecessary and invalid braces
},
{
{"$ref": "#/definitions/Encounter"} <- unnecessary and invalid braces
}
]
Within the Result property you want each item of the array. You should use the item property instead of ref. As taken from the specification:
The value of "items" MUST be either a valid JSON Schema or an array of valid JSON Schemas.
[...]
If "items" is a schema, validation succeeds if all elements in the array successfully validate against that schema.
Thus you should use
{
"type": "object",
"properties": {
"Result": {
"type": "array",
"items": {
"$ref": "#/definitions/ResultType"
}
}
}
}
Since the schema should be as specific as possible you should constraint the content of the ResourceName properties to the actual data layout.
Use the const property to define a constant value for the ResourceName for each type of Resource. Take for example the Appointment type, which would change to:
"Appointment": {
"type": "object",
"properties": {
"ResourceName": {
"const": "Appointment"
},
"Data": {
"type": "object",
"properties": {
"AppointmentID": {
"type": "string"
},
"PatientName": {
"type": "string"
},
"ClinicName": {
"type": "string"
}
}
}
}
I also changed the type of AppointmentID to string.
Then your ResultType needs to be adjusted. Before you used anyOf to validate the data, now you need it to validate the complete object while still maintaining the overall structure:
"ResultType": {
"allOf": [
{
"type": "object",
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string"
},
"Data": true
}
},
{
"anyOf": [
{
"$ref": "#/definitions/Appointment"
},
{
"$ref": "#/definitions/EpisodeofCare"
},
{
"$ref": "#/definitions/Encounter"
}
]
}
]
}
The allOf propertiy implies a and condition. The overall structure (the object) does not care what value ResourceName has or how Data is structured. The specific implementations (the anyOf part) take care of that.
Some final improvements. Use the required property to define the names of properties that must exist in your JSON file. Also add "additionalProperties": false to ensure that only the specified properties are used. And finally constraint your sequence values to be string representations of positive intergers by adding "pattern": "[1-9]\\d*".
Final result:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ResultType": {
"allOf": [
{
"type": "object",
"required": [
"ResourceName",
"Sequence",
"Data"
],
"additionalProperties": false,
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string",
"pattern": "[1-9]\\d*"
},
"Data": true
}
},
{
"anyOf": [
{
"$ref": "#/definitions/Appointment"
},
{
"$ref": "#/definitions/EpisodeofCare"
},
{
"$ref": "#/definitions/Encounter"
}
]
}
]
},
"Appointment": {
"type": "object",
"properties": {
"ResourceName": {
"const": "Appointment"
},
"Data": {
"type": "object",
"required": [
"AppointmentID",
"PatientName",
"ClinicName"
],
"additionalProperties": false,
"properties": {
"AppointmentID": {
"type": "string"
},
"PatientName": {
"type": "string"
},
"ClinicName": {
"type": "string"
}
}
}
}
},
"EpisodeofCare": {
"type": "object",
"properties": {
"ResourceName": {
"const": "EpisodeofCare"
},
"Data": {
"type": "object",
"required": [
"EpisodeID",
"LocationId",
"AppointmentId",
"TransactionStatus",
"OPNumber"
],
"additionalProperties": false,
"properties": {
"EpisodeID": {
"type": "string"
},
"LocationId": {
"type": "string"
},
"AppointmentId": {
"type": "string"
},
"TransactionStatus": {
"type": "string"
},
"OPNumber": {
"type": "string"
}
}
}
}
},
"Encounter": {
"type": "object",
"properties": {
"ResourceName": {
"const": "Encounter"
},
"Data": {
"type": "object",
"required": [
"EncounterID",
"PatientID"
],
"additionalProperties": false,
"properties": {
"EncounterID": {
"type": "string"
},
"PatientID": {
"type": "string"
}
}
}
}
}
},
"type": "object",
"required": [
"Result"
],
"additionalProperties": false,
"properties": {
"Result": {
"type": "array",
"items": {
"$ref": "#/definitions/ResultType"
}
}
}
}
you can create json schema by online tools which generates json schema from the json
like: https://www.liquid-technologies.com/online-json-to-schema-converter , it also checks if json is valid or not.
Json Schema that you need:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Result": {
"type": "array",
"items": [
{
"type": "object",
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string"
},
"Data": {
"type": "object",
"properties": {
"AppointmentID": {
"type": "string"
},
"PatientName": {
"type": "string"
},
"ClinicName": {
"type": "string"
}
},
"required": [
"AppointmentID",
"PatientName",
"ClinicName"
]
}
},
"required": [
"ResourceName",
"Sequence",
"Data"
]
},
{
"type": "object",
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string"
},
"Data": {
"type": "object",
"properties": {
"EpisodeID": {
"type": "string"
},
"LocationId": {
"type": "string"
},
"AppointmentId": {
"type": "string"
},
"TransactionStatus": {
"type": "string"
},
"OPNumber": {
"type": "string"
}
},
"required": [
"EpisodeID",
"LocationId",
"AppointmentId",
"TransactionStatus",
"OPNumber"
]
}
},
"required": [
"ResourceName",
"Sequence",
"Data"
]
},
{
"type": "object",
"properties": {
"ResourceName": {
"type": "string"
},
"Sequence": {
"type": "string"
},
"Data": {
"type": "object",
"properties": {
"EncounterID": {
"type": "string"
},
"PatientID": {
"type": "string"
}
},
"required": [
"EncounterID",
"PatientID"
]
}
},
"required": [
"ResourceName",
"Sequence",
"Data"
]
}
]
}
},
"required": [
"Result"
]
}
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.
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"] }
}
}
}
}
I am trying to build up a JSON schema, where the JSON data has an array of mixed object types. I am trying to use oneOf, however, it seems that I am missing something, as my JSON data fails to validate against the schema.
Below are what I have done so far.
Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"definitions": {
"Entity": {
"type": "object",
"additionalProperties": false,
"properties": {
"Property": {
"type": "string"
},
"Value": {
"type": "string"
}
},
"required": [ "Property", "Value" ]
},
"NavEntity": {
"type": "object",
"additionalProperties": false,
"properties": {
"Property": {
"type": "string"
},
"NavigationalEntities": {
"type": "array",
"items": {
"$ref": "#/definitions/Entity"
}
}
},
"required": [ "Property", "NavigationalEntities" ]
}
},
"additionalProperties": true,
"name": "/",
"properties": {
"Entities": {
"type": "array",
"minLength": 1,
"uniqueItems": true,
"items": {
"oneOf": [
{ "$ref": "#/definitions/Entity" },
{ "$ref": "#/definitions/NavEntity" }
],
"additionalProperties": false
}
}
}
}
And here is my JSON data:
{
"Entities": [
{
"Property": "ABC",
"NavigationalEntities": [
{
"Property": "ABC1",
"Value": "123"
}
]
},
{
"Property": "ABCD",
"Value": "ABCD"
}
]
}
When I try to validate this, I get error: "Additional properties not allowed". This can also be seen here.
Please let me know what I am missing here.
The problem is the "additionalProperties": false included in the items keyword within the Entities property.
You are specifying both:
all items should not have any additional properties that those
defined in items object (and you did not define any).
all items must verify one of Entity or NavEntity.
If you remove the last "additionalProperties": false, everything is ok. And you don't need it because both Entity and NavEntity have it included.
Proposed schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"definitions": {
"Entity": {
"type": "object",
"additionalProperties": false,
"properties": {
"Property": {
"type": "string"
},
"Value": {
"type": "string"
}
},
"required": [ "Property", "Value" ]
},
"NavEntity": {
"type": "object",
"additionalProperties": false,
"properties": {
"Property": {
"type": "string"
},
"NavigationalEntities": {
"type": "array",
"items": {
"$ref": "#/definitions/Entity"
}
}
},
"required": [ "Property", "NavigationalEntities" ]
}
},
"additionalProperties": true,
"name": "/",
"properties": {
"Entities": {
"type": "array",
"minLength": 1,
"uniqueItems": true,
"items": {
"oneOf": [
{ "$ref": "#/definitions/Entity" },
{ "$ref": "#/definitions/NavEntity" }
]
}
}
}
}