Is it possible to write a generic JSON Schema? - json

Inside my root JSON object I have many JSON objects of two different types. I'm wondering if there is a way to write a JSON schema to validate these objects without getting specific, i.e. generic schema.
For example, imagine I have the following JSON:
"Profile":
{
"Name":
{
"Type": "String",
"Value": "Mike",
"Default": "Sarah",
"Description": "This is the name of my person."
}
"Age":
{
"Type": "Number",
"Value": 27,
"Default": 18,
"Description": "This is the age of my person."
}
}
This Profile JSON object represents a collection of various details about a person. Notice I have two different types of inner Objects, String Objects and Number Objects. Taking this into account, I would now like to create a JSON Schema to validate any of the inner objects without being specifc about which Objects they are, e.g. I don't care that we have "Name" or "Age", I care that we have proper String Objects and Number Objects.
Does JSON Schema give me the ability to do this? How do I write a generic JSON Schema based on the kinds of Objects I have and not specific object names?
Here is what I've got so far:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"StringObject": {
"type": "object",
"properties": {
"Type": {
"type": "string"
},
"Value": {
"type": "string"
},
"Default": {
"type": "string"
},
"Description": {
"type": "string"
}
},
"required": [
"Type",
"Value",
"Default",
"Description"
]
}
}
}

Inside my root JSON object I have many JSON objects of two different types. I'm wondering if there is a way to write a JSON schema to validate these objects without getting specific, i.e. generic schema.
Union types are defined to handle this:
A value of the "union" type is encoded as the value of any of the member types.
Union type definition - An array with two or more items which indicates a union of type definitions. Each item in the array may be a simple type definition or a schema.
{
"type":
["string","number"]
}
References
JSON Encoding of Data Modeled with YANG: 6.10. The "union" Type
A JSON Media Type for Describing the Structure and Meaning of JSON Documents: Union Types

Related

JSON schema - support regular expression for field

I want to use the following library gojsonschema to validate json structure,
Currenlty I've two questions to the example below
https://github.com/xeipuuv/gojsonschema
what is the #/definitions/.... and what is the purpose of it?
the name should have the following:
{required: true, unique: true, pattern: '/^[A-Za-z0-9_\-\.]+$/'}
The unique is that if I've another name filed in the schema it should be unique, How can I validate it with jsonschema?
var schema = `
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"name": ...
"properties": {
"username": {"$ref": "#/definitions/name"},
update
what I found is this
https://spacetelescope.github.io/understanding-json-schema/reference/regular_expressions.html
But how should I check it inside the json i've provided
should It be like this
var schema = `
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"name": {
"type": "object",
"pattern":'/^[A-Za-z0-9_\-\.]+$/'
}
"properties": {
"username": {"$ref": "#/definitions/name"},
https://datatracker.ietf.org/doc/draft-handrews-json-schema-validation/?include_text=1
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"username": {
"type": "array",
"items": {
"type": "string",
"pattern": "/^[A-Za-z0-9_\-\.]+$/"
},
"uniqueItems": true
}
},
"required": [
"username"
]
}
1: The "definitions" keywords provides a standardized location for
schema authors to inline re-usable JSON Schemas into a more general
schema. The keyword does not directly affect the validation result.
This keyword's value MUST be an object. Each member value of this
object MUST be a valid JSON Schema.
As an example, here is a schema describing an array of positive
integers, where the positive integer constraint is a subschema in
"definitions":
{
"type": "array",
"items": { "$ref": "#/definitions/positiveInteger" },
"definitions": {
"positiveInteger": {
"type": "integer",
"exclusiveMinimum": 0
}
}
}
2: uniqueItems
The value of this keyword MUST be a boolean.
If this keyword has boolean value false, the instance validates
successfully. If it has boolean value true, the instance validates
successfully if all of its elements are unique.
Omitting this keyword has the same behavior as a value of false.
required
The value of this keyword MUST be an array. Elements of this array,
if any, MUST be strings, and MUST be unique.
An object instance is valid against this keyword if every item in the
array is the name of a property in the instance.
Omitting this keyword has the same behavior as an empty array.
properties
{
"type": "object",
"properties": {
"progBinaryName": {
"type": "string",
"pattern": "^[A-Za-z0-9 -_]+_Prog\\.(exe|EXE)$"
}
}
}
The value of "properties" MUST be an object. Each value of this
object MUST be a valid JSON Schema.
This keyword determines how child instances validate for objects, and
does not directly validate the immediate instance itself.
Validation succeeds if, for each name that appears in both the
instance and as a name within this keyword's value, the child
instance for that name successfully validates against the
corresponding schema.
Omitting this keyword has the same behavior as an empty object.
#/definitions/name is an internal reference to another schema. The document should have section that looks like the following that is being referenced:
"definitions": {
"name": {
...
}
}
JSON schema does not have a unique validator. There is a uniqueItems validator that can be used with arrays but I don't think that is what you are looking for.

How to validate for nullable types using json schema validator?

I'm using the play-json-schema-validator and want to set up an integration test with scala in order to check an API's JSON response schema.
Certain fields of the response are nullable and I want to validate for that. So some field can be either a string or null yet it can never be a number.
Playing around on its playground I want to validate for an array of objects that each object's name property is either a string or null.
I came up with this schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"name": {
"type": ["string", null]
}
}
}
}
Yet though it validates the string and null case, I now get a false positive for numbers. I was expecting an error for this json, yet it validates:
[
{
"name": "Red anger"
},
{
"name": null
},
{
"name": 13
}
]
How to declare a field of a type as nullable using schema validator?
Enquote the null in the schema:
"type": ["string", "null"]
You can read about that in the json schema validation documentation, i.e.:
6.1. Validation Keywords for Any Instance Type
6.1.1. type
The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and
MUST be unique.
String values MUST be one of the six primitive types ("null",
"boolean", "object", "array", "number", or "string"), or "integer"
which matches any number with a zero fractional part.
An instance validates if and only if the instance is in any of the
sets listed for this keyword.
The type attribute of the schema does not accept arrays but only a single type at the time:
"string", "null"... and as you pointed out, the types should be strings so instead of null => "null"
If you want to check multiple types for a single field you need to use
anyOf, oneOf, allOf
Here is an example working with your input
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product set",
"type": "array",
"items": {
"title": "Product",
"type": "object",
"properties": {
"name": {
"anyOf": [
{"type":"string"},
{"type":"null"},
{"type":"number"}
]
}
}
}
}

Restrict JSON values to the names of other JSON objects

I'd like to use JSON schema to validate some values. I two objects, call them trackedItems and trackedItemGroups. The trackedItemGroups are a group name and a list of trackedItems names. For example, the schema is similar to:
"TrackedItems": {
"type": "array",
"items": {
"type": "object",
"properties": {
"TrackedItemName": { "type": "string" },
"Properties": { ---- }
}
}
},
"TrackedItemGroups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"GroupName": {
"type": "string"
},
"TrackedItems": {
"type": "array",
"items": {"type": "string"}
}
}
}
}
I'd like to validate that every string in a TrackedItemGroups's TrackedItems array is a name that's been defined in TrackedItems.TrackedItemName.
This would be something like using the enum property to restrict the values, but the enum list is generated based on the values in TrackedITems.TrackedItemName.
How can I write the schema to use the JSON's own data for validation?
I'm aware I could move things around, i.e. the TrackedItems define the group they're in, but there are hundreds of tracked items and this organization works much better for my use case.
I've tried this:
"TrackedItems": {
"type": "array",
"items": {
"oneOf": [
{"$ref":"#/properties/TrackedItems/items/properties/TrackedItemName"}
]
}
}
But this results in an error:
Newtonsoft.Json.Schema.JSchemaReaderException: Could not resolve
schema reference
'#/properties/TrackedItems/items/properties/TrackedItemName'.
For a data example, if I had the TrackedItems:
Item1, Item2, ItemA, ItemB, ItemC
And groups:
Group1:
Item1, ItemB, ItemC
Group2:
Item1, Item2, ItemZ
Group2 would throw a violation because it contains an item not defined in TrackedItems.
Being a vocabulary for validation (and certain other things described by trivial assertions), JSON Schema does not provide a way to verify the consistency of data.
Validation means assertions like "Verify that X is a string."
Consistency means things like "Verify that X is the ID of an existing, active user."
Since data being compared might be in another database altogether, and since these sorts of assertions are non-trivial, JSON Schema leaves verifying the consistency of data up to the application and/or other technologies. Some implementations have vendor-specific extensions for intra-document comparisons, however these are not standardized, and I'm not aware of any that would work here.
A $ref reference doesn't work here, as it's just a way to substitute in another schema by reference. If you can manage to get the reference to work (and I'm not sure why you got an error, this is implementation-specific detail), this schema:
{ "oneOf": [
{"$ref":"#/properties/TrackedItems/items/properties/TrackedItemName"}
] }
Is the exact same thing as saying:
{ "oneOf": [
{"type": "string"}
] }
Since you're asking "verify that one of the following one statements is true", this is also the same as simply:
{"type": "string"}
This is not to say you can't declare relationships between data in JSON using JSON Schema, but JSON Schema is somewhat opinionated about using URIs and hyperlinks to do so.

Creating a type definition for a property named "type" using JSON schema

I'm trying to create a JSON schema for an existing JSON file that looks something like this:
{
"variable": {
"name": "age",
"type": "integer"
}
}
In the schema, I want to ensure the type property has the value string or integer:
{
"variable": {
"name": "string",
"type": {
"type": "string",
"enum": ["string", "integer"]
}
}
}
Unfortunately it blows up with message: ValidationError {is not any of [subschema 0]....
I've read that there are "no reserved words" in JSON schema, so I assume a type of type is valid, assuming I declare it correctly?
The accepted answer from jruizaranguren doesn't actually answer the question.
The problem is that given JSON (not JSON schema, JSON data) that has a field named "type", it's hard to write a JSON schema that doesn't choke.
Imagine that you have an existing JSON data feed (data, not schema) that contains:
"ids": [ { "type": "SSN", "value": "123-45-6789" },
{ "type": "pay", "value": "8675309" } ]
What I've found in trying to work through the same problem is that instead of putting
"properties": {
"type": { <======= validation chokes on this
"type": "string"
}
you can put
"patternProperties": {
"^type$": {
"type": "string"
}
but I'm still working through how to mark it as a required field. It may not be possible.
I think, based on looking at the "schema" in the original question, that JSON schemas have evolved quite a lot since then - but this is still a problem. There may be a better solution.
According to the specification, in the Valid typessection for type:
The value of this keyword MUST be either a string or an array. If it is an array, elements of the array MUST be strings and MUST be unique.
String values MUST be one of the seven primitive types defined by the core specification.
Later, in Conditions for successful validation:
An instance matches successfully if its primitive type is one of the types defined by keyword. Recall: "number" includes "integer".
In your case:
{
"variable": {
"name": "string",
"type": ["string", "integer"]
}
}

How to define custom object type in json-schema

Suppose I have couple of objects like Vehicle and Computer.
{"brand":"Ford", "dateOfManufacture":"23/082015"}
{"brand":"Apple", "dateOfManufacture":"23/082015"}
I know I can represent vehicle schema like below. However looking at schema doesn't tell me if its of Object type Vehicle or Computer. How can put that information in JSON. Do json-schema provide custom type support . So instead of saying "type": "object" can I say "type": "vehicle".
{
"description": "schema validating people",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"firstName": {"type": "string"},
"lastName": {"type": "string"}
}
}
}
TIA
While you can't define a new type explicitly, you can define a schema describing what objects of that type look like, and then reference it in your master schema.
{
"$schema": "http://json-schema.org/draft-07/schema",
"definitions": {
"vehicle": {
"type": "object",
"properties": {
"brand": {
"type": "string",
"enum": ["ford","toyota"]
},
"dateOfManufacture": {
"type": "string"
}
}
}
},
"type": "object",
"properties": {
"primary": { "$ref": "#/definitions/vehicle" },
"secondary": { "$ref": "#/definitions/vehicle" }
}
}
This example describes an object with fields primary and secondary that are both of "type" vehicle - i.e. the data must match the schema that describes what a vehicle looks like.
In typed programming languages, the concept of type is used to communicate the shape of data, but also something about the identity of that data - i.e. it gives an identity, or name, to the specific definition of a structure.
struct Foo { int a; string b; }
struct Bar { int a; string b; }
function quux(Foo foo) { ... }
In this dummy example, you can't pass a Bar into Quux, even though it looks just like a Foo. This is because in addition to describing the shape of the data (int a; string b;), the type defines an identity to the data structure.
JsonSchema is about describing the shape of data - i.e. how primitive types are combined in some kind of structure, but says nothing about the identity. It cares about the names of fields and how they are structured, but doesn't care about what you called the schema (or analogously, the name of the struct).
You can add product type also in schema like:-
{"brand":"Ford", "dateOfManufacture":"23/082015", "productType":"vehicle"}
{"brand":"Apple", "dateOfManufacture":"23/082015", "productType":"computer"}
While deciding schema, you can ensure that it has all the necessary information for the classification of products.