I am trying to validate JSON file against this schema including dateTime regex pattern:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://example.com/product.schema.json",
"title": "title",
"type": "object",
"properties": {
"entries": {
"description": "date time entries",
"type": "array",
"contains": {
"type": "object"
},
"items": {
"type": "object",
"properties": {
"dateTime": {
"description": "UTC timestamp in format \"YYYY-MM-DDThh:mm:ssTZD\" according to ISO 8601",
"type": "string",
"pattern": "^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]{3})?(?:Z|[+-][01][0-9]:[0-5][0-9])?$"
}
}
}
}
}
}
When I try to validate this JSON file:
{
"description": "date time entries",
"entries": [
{
"dateTime": "2020-10-09T08:48:41.348+02:00"
},
{
"dateTime": "2020-10-09T08:48:52.240+02:00"
}
]
}
I get the following error regarding second entry in the array:
String '2020-10-09T06:48:52.24+00:00' does not match regex pattern '^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]{3})?(?:Z|[+-][01][0-9]:[0-5][0-9])?$'.
Please note, that the validator correctly validated 1st entry: "2020-10-09T08:48:41.348+02:00".
What I noticed is that the problem is with entries containing milliseconds with "0" at the end, like: ".240"
Related
I have a JSON schema that contains "$ref" tags and I am trying to get a version of the JSON schema that have the "$ref" tags resolved. I am only looking to resolve "$ref" from definition (tags) within the JSON Schema string (ie. not external resolution needed).
Is there a library that performs the resolution of the JSON Schema? (I am currently using org.everit.json.schema library, which is great, but I can't find how to do what I need).
For example, my original schema is:
{
"$id": "https://example.com/arrays.schema.json",
"description": "A representation of a person, company, organization, or place",
"title": "complex-schema",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": { "$ref": "#/$defs/veggie" }
}
},
"$defs": {
"veggie": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
Which would resolve to something like this (notice that the "#defs/veggie" resolves to its definition inserted inline in the schema):
{
"$id": "https://example.com/arrays.schema.json",
"description": "A representation of a person, company, organization, or place",
"title": "complex-schema",
"type": "object",
"properties": {
"fruits": {
"type": "array",
"items": {
"type": "string"
}
},
"vegetables": {
"type": "array",
"items": {
"type": "object",
"required": [ "veggieName", "veggieLike" ],
"properties": {
"veggieName": {
"type": "string",
"description": "The name of the vegetable."
},
"veggieLike": {
"type": "boolean",
"description": "Do I like this vegetable?"
}
}
}
}
}
}
This isn't possible in the general sense, because:
the $ref might be recursive (i.e. reference itself again)
the keywords in the $ref might duplicate some of the keywords in the containing schema, which would cause some logic to be overwritten.
Why do you need to alter the schema in this way? Generally, a JSON Schema implementation will resolve the $refs automatically while evaluating the schema against provided data.
I want to write a single file JSON schema definition with several sub schemas that I can combine, depending on the payload.
The following schema validates, that my schema is working with my sample JSON response. (The response object has a wrong type for payload.role to make sure the schema catches this mistake!)
For clarity, I reduce it on the most important parts. A full working example can be found here: https://www.jsonschemavalidator.net/s/3KAaXjtg
Schema
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/baseSchema.json",
"type": "object",
"required": [
"payload"
],
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
// reference the right schema depending on the payload child key
// if `payload.user` reference `userSchema.json`
// if `payload.users` reference `usersSchema.json`
// if `payload.*` reference `*Schema.json`
"$ref": "userSchema.json"
}
},
"definitions": {
"user": {
"$id": "http://example.com/userSchema.json",
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"type": "object",
"$ref": "userProperties.json"
}
}
},
"users": {
"$id": "http://example.com/usersSchema.json",
"type": "object",
"required": [
"users"
],
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "userProperties.json"
}
}
}
},
"userProperties": {
"$id": "http://example.com/userProperties.json",
"type": "object",
"properties": {
"firstName": {
"$id": "#/properties/payload/properties/user/properties/firstName",
"type": "string"
}
}
}
}
}
Response
{
"status": {
"code": 200,
"description": "User retrieved successfully."
},
"payload": {
"user": {
"firstName": "Joe",
"lastName": "Doe",
"role": "3", // for testing reasons, this is the wrong type!
"email": "doe#example.com",
"customerID": "",
"projects": [
"AIXG5mEg6QLl9rhVSE6m",
"Bs1bHiOIqKclwwis3CNf",
"NC2OUGVZXU35FA7iwRn4"
],
"status": "Status",
"id": "c555BSZnKLdHSRYqrU5hqiQo733j13"
}
}
}
So I've got a baseSchema.json that matches this response:
{
"status": {},
"payload": {}
}
payload gets extended by a certain key like payload.user = {} or payload.foo = {} and depending on that key, I want to extend schema with one of my definitions.
The following part only works for the key user:
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
// reference the right schema depending on the payload child key
// if `payload.user` reference `userSchema.json`
// if `payload.users` reference `usersSchema.json`
// if `payload.*` reference `*Schema.json`
"$ref": "userSchema.json"
}
},
I failed to setup any conditions (with allOf, if, else), that would reference the correct sub-schema, based on the payload key.
Any hints and help to solve that is appreciated.
Schema and link to demo at the end... Let's look at how we got there...
In JSON Schema draft-07 and previous, you can't use $ref alongside other keywords. Other keywords are ignored. (In your schema http://example.com/userSchema.json you had type next to $ref). Fortunatly this didn't cause you any problems as you declare the type in the referenced schema. (You CAN do this with 2019-09 or above.)
The values for the keywords if, then, and else are schemas.
For the then subschema to be applied to your instance location, the if schema must come back as valid. If it fails, the else subschema value will be applied.
Our if condition checks for the presense of a specific key.
If the key exists, THEN apply the schema which references the correct schema.
Because you want the conditions to be mutually exclusive, you need to wrap the multiple conditions in a oneOf, and add else: false to the conditional checks. false as a schema makes validation fail.
Let me know if you want any further clarification on any of the above.
Demo: https://jsonschema.dev/s/HLniL
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "http://example.com/baseSchema.json",
"type": "object",
"required": [
"payload"
],
"properties": {
"payload": {
"$id": "#/properties/payload",
"type": "object",
"oneOf": [
{
"if": {
"required": [
"user"
]
},
"then": {
"$ref": "userSchema.json"
},
"else": false
},
{
"if": {
"required": [
"users"
]
},
"then": {
"$ref": "usersSchema.json"
},
"else": false
}
]
}
},
"definitions": {
"user": {
"$id": "http://example.com/userSchema.json",
"type": "object",
"required": [
"user"
],
"properties": {
"user": {
"$ref": "userProperties.json"
}
}
},
"users": {
"$id": "http://example.com/usersSchema.json",
"type": "object",
"required": [
"users"
],
"properties": {
"users": {
"type": "array",
"items": {
"$ref": "userProperties.json"
}
}
}
},
"userProperties": {
"$id": "http://example.com/userProperties.json",
"type": "object",
"properties": {
"firstName": {
"type": "string"
}
}
}
}
}
I have a JSON object like:
{
"result": [
{
"name" : "abc",
"email": "abc.test#mail.com"
},
{
"name": "def",
"email": "def.test#mail.com"
},
{
"name": "xyz",
"email": "abc.test#mail.com"
}
]
}
and schema for this:
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://example.com/object1607582431.json",
"title": "Root",
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"$id": "#root/result",
"title": "Result",
"type": "array",
"default": [],
"uniqueItems": true,
"items": {
"$id": "#root/result/items",
"title": "Items",
"type": "object",
"required": [
"name",
"email"
],
"properties": {
"name": {
"$id": "#root/result/items/name",
"title": "Name",
"type": "string"
},
"email": {
"$id": "#root/result/items/email",
"title": "Email",
"type": "string"
}
}
}
}
}
}
I am looking for an option to check uniqueness for email irrespective of name. How I can validate that every email should be unique?
You can't. There are no keywords that let you compare one particular data value against another, other than uniqueItems, which compares an array element in toto against another.
The JsonSchema specification does not currently support this.
You can see the active GitHub issue here: https://github.com/json-schema-org/json-schema-vocabularies/issues/22
However, there are various extensions of JsonSchema that do validate unique fields within lists of objects.
If you happen to be using Python you can use the package (I created) JsonVL. It can be installed with pip install jsonvl and then run with jsonvl data.json schema.json.
Code examples in the GitHub repo: https://github.com/gregorybchris/jsonvl
I have JSON data of which is an array of data like
[
{
"type": "background_color",
"data": {
"backgroundColor": "F9192D"
}
},
{
"type": "banner_images",
"data": {
"images": [
{
"url": "https://example.com/abc.jpg",
"id": 3085
},
{
"url": "https://example.com/zyx.jpg",
"id": 3086
}
]
}
},
{
"type": "description_box",
"data": {
"text": "Hello 56787"
}
}
]
The data is an array of object which has two keys type and data. The type and keys of the data will be defined by the type of data it has.
Like for background_color type, the data should have backgroundColor property, while for banner_images, data should have images which is an array of other properties.
Till now, What I have done is
{
"definitions": {},
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"examples": [],
"required": [],
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": ["background_color", "banner_images", "description_box"]
},
"data": {
"type": "object" // How to define data property here for each use case
}
}
}
}
I'm not getting how to define the data property for each use case?
You can use if/then/else blocks to define conditional constraints.
The values of if and then are schemas. If the if schema is valid, then the then schema is applied, otherwise, the allOf subschema (allOf[0] in this example) would pass validation.
There are a few different ways to do this, but this is clean when you don't have any additional or special requirements. Please come back if you do =]
In this example, I've added banner_images...
You can test it working here.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "array",
"title": "category schema",
"description": "Used to validate data of category",
"items": {
"type": "object",
"required": [
"type",
"data"
],
"properties": {
"type": {
"type": "string",
"enum": [
"background_color",
"banner_images",
"description_box"
]
},
"data": {
"type": "object"
}
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": "banner_images"
}
}
},
"then": {
"properties": {
"data": {
"required": [
"images"
],
"properties": {
"images": {
"type": "array"
}
}
}
}
}
}
]
}
}
For reference, here's the part of the JSON Schema draft-7 spec document that details the behaviour: https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-validation-01#section-6.6
I want to validate my API json response like this:
{
"code": 0,
"results": [
{"type":1, "abc": 123},
{"type":2, "def": 456}
]
}
I want to validate the objects within results to have a "abc" field when its type is 1, and "def" field when its type is 2. The results may contain arbitrary number of type1 and type2 objects.
Can I specify this in jsonschema? Or must I use a generic validator for elements in results and do validation myself?
You can do this using the anyOf keyword.
An instance validates successfully against this keyword if it validates successfully against at least one schema defined by this keyword's value.
http://json-schema.org/latest/json-schema-validation.html#anchor85
You need to define both types of items and then use anyOf To describe the array items for "results".
{
"type": "object",
"properties": {
"code": { "type": "integer" },
"results": {
"type": "array",
"items": { "$ref": "#/definitions/resultItems" }
}
},
"definitions": {
"resultItems": {
"type": "object",
"anyOf": [
{ "$ref": "#/definitions/type1" },
{ "$ref": "#/definitions/type2" }
]
},
"type1": {
"properties": {
"type": { "enum": [1] },
"abc": { "type": "integer" }
},
"required": ["abc"]
},
"type2": {
"properties": {
"type": { "enum": [2] },
"def": { "type": "integer" }
},
"required": ["def"]
}
}
}