jsonschema for array type validates incorrect data, how to fix? - jsonschema

I have following jsonschema:
{
"$schema": "http://json-schema.org/schema#",
"type": "object",
"properties": {
"abc": {
"type": "array",
"item": {
"type": "object",
"minItems": 1,
"properties": {
"a" : {"type": "string"},
"b" : {"type": "string"}
},
"required": [ "a", "b" ]
}
}
},
"required": [ "abc" ]
}
If I pass to validator following data:
{
"abc": [
{
},
{
}
]
}
validator will output no error, but such data incorrect.

You used item rather than items.
Additionally, "minItems": 1 needs to be moved up to the parent object.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"abc": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"a": {
"type": "string"
},
"b": {
"type": "string"
}
},
"required": [
"a",
"b"
]
}
}
},
"required": [
"abc"
]
}
Checked and validated using https://jsonschema.dev

Related

Easy way to group custom defined types to use for reference?

How to reference types by group instead of doing it individually?
For example here, I want "sum" and "subtract" types to accept types that are "number"-related types only("number", "sum", "subtract"). While "concatenate" can accept both "number" and "string"-related types. Including their selves. This will be really helpful for me if in case I added more types and want them to be automatically included.
"sum": {
"title": "sum",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"values"
]
},
"subtract": {
"title": "subtract",
"type": "object",
"properties": {
"minuend": {
"type": "number"
},
"subtrahend": {
"type": "number"
}
},
"required": [
"minuend",
"subtrahend"
]
},
"concatenate": {
"title": "concatenate",
"type": "object",
"properties": {
"strings": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"strings"
]
}
}
Here's the full schema:
{
"definitions": {
"sum": {
"title": "sum",
"type": "object",
"properties": {
"values": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"values"
]
},
"subtract": {
"title": "subtract",
"type": "object",
"properties": {
"minuend": {
"type": "number"
},
"subtrahend": {
"type": "number"
}
},
"required": [
"minuend",
"subtrahend"
]
},
"concatenate": {
"title": "concatenate",
"type": "object",
"properties": {
"strings": {
"type": "array",
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "string"
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
},
"required": [
"strings"
]
}
},
"title": "Step",
"type": "object",
"properties": {
"value": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"$ref": "#/definitions/sum"
},
{
"$ref": "#/definitions/subtract"
}
]
}
}
}

json schema validation: a string field required if another array field contains specific value

cant build validation for simple case:
if sources field contains "OTHER" in values then "sourceOtherDescription" must be required.
Shall pass validation
{
"sources": ["RENTS"]
}
{
"sources": ["RENTS", "OTHER"],
"sourceOtherDescription": "other income"
}
This should not pass validation since sources contains "OTHER"
{
"sources": ["RENTS", "OTHER"]
}
The schema that I was able to produce. Does not really work
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "money-sources",
"title": "Money Sources",
"description": "Money Sources definitions",
"type": "object",
"required": ["sources"],
"properties": {
"sources": {
"type": "array",
"items": {
"type": "string",
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES",
"INTERNAL_GROUP_TRANSFERS",
"OTHER"
]
},
"uniqueItems": true
},
"sourceOtherDescription": { "type": "string", "minLength": 3}
},
"additionalProperties": false,
"oneOf": [
{
"properties": {
"sources": {
"type": "array",
"contains": {"const": "OTHER"}
}
},
"required": ["sourceOtherDescription"]
},
{
"properties": {
"sources": {
"type": "array",
"contains": {
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES"
]
}
}
}
}
, false
]
}
Using if-then it works for me this way:
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "money-sources",
"title": "Money Sources",
"description": "Money Sources definitions",
"type": "object",
"required": [ "sources" ],
"properties": {
"sources": {
"type": "array",
"items": {
"type": "string",
"enum": [
"RENTS",
"MEMBER_FEES",
"PROFIT",
"SALES_SECURITIES",
"INTERNAL_GROUP_TRANSFERS",
"OTHER"
]
},
"uniqueItems": true
},
"sourceOtherDescription": {
"type": "string",
"minLength": 3
}
},
"additionalProperties": false,
"if": {
"properties": {
"sources": {
"type": "array",
"contains": {
"const": "OTHER"
}
}
}
},
"then": {
"required": [ "sourceOtherDescription" ]
}
}

Generic json schema for two condition based responses

I have an API returning response based on input type.
For a single filter I get
{
"intervalData": [
{
"timestamp": "2021-05-25T06:00:00.000Z",
"result": {
"Attempts": 309194
}
}
],
"intervalTotals": {
"Attempts": 4719471
}
}
For multiple filter I get
{
"multiFilterData": [
{
"filter": {
"id": 111111
},
"intervalData": {
"timestamp": "2021-05-25T20:41:39.000Z",
"result": {
"Attempts": 7902
}
}
},
{...}
]
}
That means the response will either have (intervalData,intervalTotals) OR multiFilterData.
Question:
Is it possible to have a generic schema to handle this or must I have two separate schemas?
How to make sure that if one combination is present other should not be there?
I tried with below schema on https://www.jsonschemavalidator.net/. The validation fails if there is some other keys listed under the required, unfortunately the validation succeeds if one of the entry from oneOf is missing. EDIT1 below
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"oneOf": [
{
"required": [
"intervalData",
"intervalTotals",
]
},
{
"required": [
"multiFilterData",
]
}
],
"properties": {
"intervalData": {
"type": "array",
"additionalItems": false,
"items": {
"type": "object",
"required": [
"timestamp",
"result"
],
"properties": {
...
},
"additionalProperties": false
}
},
"intervalTotals": {
"type": "object",
"required": [
"Attempts"
],
"properties": {
"Attempts": {
"type": "integer"
}
},
"additionalProperties": false
},
"multiFilterData": {
"type": "array",
"additionalItems": false,
"items": {
"type": "object",
"required": [
"filter",
"intervalData"
],
"properties": {
"filter": {
"type": "object",
"required": [
"id"
],
"properties": {
"id": {
"type": "integer"
}
},
"additionalProperties": false
},
"intervalData": {
"type": "object",
"required": [
"timestamp",
"result"
],
"properties": {
"timestamp": {
"type": "string"
},
"result": {
"type": "object",
"required": [
"Attempts"
],
"properties": {
...
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}
EDIT 1: This schema also passes even though the first required is missing an element on the list.
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"oneOf": [
{
"required": [
"intervalData"
]
},
{
"required": [
"multiFilterData",
]
}
],
"properties": {
"intervalData": {...},
"intervalTotals": {...},
"multiFilterData": {...}
},
"additionalProperties": false
}

Using a json schema in multiple layouts

I'm helping to build an interface that works with Json Schema, and I have a question about interface generation based on that schema. There are two display types - one for internal users and one for external users. Both are dealing with the same data, but the external users should see a smaller subset of fields than the internal users.
For example, here is one schema, it defines an obituary:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "",
"type": "object",
"required": [
"id",
"deceased"
],
"properties": {
"id": { "type": "string" },
"account": {
"type": "object",
"required": [
"name"
],
"properties": {
"id": { "type": "number" },
"name": { "type": "string" },
"website": {
"anyOf": [
{
"type": "string",
"format": "uri"
},
{
"type": "string",
"maxLength": 0
}
]
},
"email": {
"anyOf": [
{
"type": "string",
"format": "email"
},
{
"type": "string",
"maxLength": 0
}
]
},
"address": {
"type": "object",
"properties": {
"address1": { "type": "string" },
"address2": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"postalCode": { "type": "string" },
"country": { "type": "string" }
}
},
"phoneNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"faxNumber": {
"anyOf": [
{
"type": "string",
"format": "phone"
},
{
"type": "string",
"maxLength": 0
}
]
},
"type": { "type": "string" }
}
},
"deceased": {
"type": "object",
"required": [
"fullName"
],
"properties": {
"fullName": { "type": "string" },
"prefix": { "type": "string" },
"firstName": { "type": "string" },
"middleName": { "type": "string" },
"nickName": { "type": "string" },
"lastName1": { "type": "string" },
"lastName2": { "type": "string" },
"maidenName": { "type": "string" },
"suffix": { "type": "string" }
}
},
"description": { "type": "string" },
"photos": {
"type": "array",
"items": { "type": "string" }
}
}
}
Internal users would be able to access all the fields, but external users shouldn't be able to read/write the account fields.
Should I make a second schema for the external users, or is there a way to indicate different display levels or public/private on each field?
You cannot restrict acess to the fields defined in a schema, but you can have 2 schema files, one defining the "public" fields, and the other one defining the restricted fields plus including the restricted fields.
So
public-schema.json:
{
"properties" : {
"id" : ...
}
}
restricted-schema.json:
{
"allOf" : [
{
"$ref" : "./public-schema.json"
},
{
"properties" : {
"account": ...
}
}
]
}

JSON schema for object with either A and B or C required properties

I have two possible JSON objects for one request:
{
"from": "string",
"to": "string",
"text": "string"
}
or
{
"number": "integer",
"text": "string"
}
In both cases "text" property is optional. Other properties are required (either "number, or both "from" and "to").
What will be the correct JSON schema to validate this?
Here is another solution that I think is a bit more clear. The dependencies clause ensures that "from" and "to" always come as a pair. Then the oneOf clause can be really simple and avoid the not-required boilerplate.
{
"type": "object",
"properties": {
"from": { "type": "string" },
"to": { "type": "string" },
"number": { "type": "integer" },
"text": { "type": "string" }
},
"dependencies": {
"from": ["to"],
"to": ["from"]
},
"oneOf": [
{ "required": ["from"] },
{ "required": ["number"] }
]
}
Finally managed to build the correct scheme.
{
"definitions": {
"interval": {
"type": "object",
"properties": {
"from": {
"type": "string"
},
"to": {
"type": "string"
},
"text": {
"type": "string"
}
},
"required": ["from", "to"],
"not": {
"required": ["number"]
}
},
"top": {
"type": "object",
"properties": {
"number": {
"type": "integer"
},
"text": {
"type": "string"
}
},
"required": ["number"],
"allOf": [
{
"not": {
"required": ["from"]
}
},
{
"not": {
"required": ["to"]
}
}
]
}
},
"type": "object",
"oneOf": [
{"$ref": "#/definitions/interval"},
{"$ref": "#/definitions/top"}
]
}