Json schema in draftv3 - json

Request:
{
"PersonSearch":
{
"LastName": "Doe",
"Gender":"Male",
"State" : "FL"
}
}
or
{
"PersonSearch":
{
"FirstName": "John",
"Gender":"Male",
"State" : "FL"
}
}
What is the json schema that I can validate both requests.
It has to be compatible with drraftV3.

Your requirements seem to be that you need either "FirstName" or "LastName", correct?
There is no way to specify a single schema that works for both v4 and v3, because of some fundamental changes in the spec: in v4 type can only hold a string (or array of strings). It is not permitted to use schemas inside type.
You should avoid using v3 if possible, and move over to v4.
v4 method:
In that case, you'll need to use anyOf for that particular constraint:
{
"type": "object",
"anyOf": [
{"required": ["FirstName"]},
{"required": ["LastName"]}
],
"properties": {...}
}
v3
In v3 syntax, you use type instead of anyOf (also, required is a boolean):
{
"type": [
{
"type": "object",
"properties": {
"FirstName": {"required": true}
}
},
{
"type": "object",
"properties": {
"LastName": {"required": true}
}
}
],
"properties": {...}
}
v3 -> v4 conversion
If you're stuck with a mixture of v3/v4 schemas, this tool (json-schema-compatibility) will normalise schemas (v3 or v4) into v4 syntax.
If you're working in JavaScript, you can run the schemas through the compatibility tool before you use them. You can then use purely v4-tools for your actual validation/whatever.

Related

Structuring JSON schema with hierarchical definitions

I'm new in writing JSON schemas. I thought I could use the following structure in my schema file. What do you think, is this feasible?
{
"properties": {
"my_object": {
"$ref": "#/definitions/my_object"
}
},
"formats": {
"language": {
"type": "string",
"pattern": "^[a-z]{2}-[A-Z]{2}$"
},
"zipcode": {
"type": "string",
"pattern": "\\d{5}-\\d{4}|\\d{5}"
}
},
"definitions": {
"my_object": {
"type": "object",
"properties": {
"language": {"$ref": "#/formats/language"},
"zipcode": {"$ref": "#/formats/zipcode"}
}
}
}
}
The top level only contains references to objects under definition. Since I need some type & pattern pairs more than once I put them under formats.
Is definitions a key word in JSON schema? At least it is widely used in examples. Is it ok to add your own "key words" like formats here or should everything go under definitions?
While a lot of examples indeed use definitions it is outdated and the recommended way is to use $defs instead. Other keys are still supported to be backwards compatible. See here for more
Thus, I'd recommend keeping all sub-schemas in the $defs object. It is still possible to to group semantically related sub-schemas inside $defs so if you insist on keeping the the distinction you can do something like this:
{
"properties":{
"my_object":{
"$ref":"#/$defs/my_object"
}
},
"$defs":{
"my_object":{
"type":"object",
"properties":{
"language":{
"$ref":"#/$defs/formats/language"
},
"zipcode":{
"$ref":"#/$defs/formats/zipcode"
}
}
},
"formats":{
"language":{
"type":"string",
"pattern":"^[a-z]{2}-[A-Z]{2}$"
},
"zipcode":{
"type":"string",
"pattern":"\\d{5}-\\d{4}|\\d{5}"
}
}
}
}

JSON Schema object with primitive type or $ref type?

I have a schema in which a particular property (child) can be either a string or it can be an object I already have defined (ChildClass). I'm having a hard time defining this in the schema, however:
{
definitions": {
"ChildClass": { ... },
"ParentClass": {
"description": "The parent object",
"type": [ "object" ],
"properties": {
"child": {
"anyOf": [
{ "$ref": "#/definitions/ChildClass" },
"string"
]
}
}
}
}
}
I can use either the "string" definition or my referenced definition, but not both together (with anyOf). What's the appropriate syntax to allow the schema to understand that either one of these is valid?
The anyOf keyword requires schemas as its items. "string" is not in itself a schema. Try using
{"type": "string"}
inside the anyOf alongside your ChildClass reference.

Validate each JSON node with different JSON schema

Im trying to make a system monitor, which is highly customisable by user. This customization is achieved by using JSON file for modeling look of system monitor. The JSON could look like this.
{
"_": "WINDOW",
"name": "myWindow",
"children": [
{
"_": "CPU",
"name": "cpuMonitor",
"freq_Unit": "MHZ"
},
{
"_": "NETWORK",
"name": "network",
"unit": "Kb/s"
},
{
"_": "DISK",
"name": "disk"
}
],
"background": "red"
}
As you can see, each object coresponds to this schema.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"name":"Component",
"type": "object",
"properties":{
"_": {
"type": "string"
},
"name":{
"type":"string"
},
"childern":{
"type":"array"
}
},
"required": ["_","name"]
}
But each component has also its own schema definition. I'd like to parse whole JSON and validate each node for different schema (first if its component and then to its corresponding schema).
I had look at rapidJson and other libraries, but I didnt find solution for validating nodes for different schema. Do you know any library which could do that? Or is it even possible to validate JSON in this way?
All feedback on how to solve this will be appreciated.
Edit: Corrected schema :(
There's a simple approach involved with that, use the oneOf pattern declaration to specify the layout of the array elements. Inside these nested declarations, you specify the fixed identifier (probably the content of your _ field) as a constant, so that there is only one nested schema matching each of your panel types.
Notes:
I had to specify the constant type identifier using the enum specifier because the regular constant specifier didn't work with the library I was using. This may also have been an oversight in the revision of the specification that it was based on.
A different approach is to split the the validation steps. You simply verify that the elements of the array are objects and that they have a string field _ containing one of the supported types. When iterating over the array, you then validate each field individually according to its _ field.
In addition to Ulrich's answer, here's an example of what I'd do:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Component",
"type": "object",
"definitions": {
"base": {
"properties": {
"name": { "type": "string" },
"children": {
"type": "array",
"items": { "$ref": "#" }
}
},
"required": [ "_", "name" ]
},
"cpu": {
"properties": {
"_": { "const": "CPU" },
"freq_Unit": "MHZ"
}
},
"network": {
"properties": {
"_": { "const": "NETWORK" },
"unit": "Kb/s"
}
},
"disk": {
"properties": {
"_": { "const": "DISK" }
}
},
"window": {
"properties": {
"_": { "const": "WINDOW" },
"background": { "enum": [ "red", "orange", "yellow", ... ] }
}
}
},
"allOf": [
{ "$ref": "#/definitions/base" },
{
"oneOf": [
{ "$ref": "#/definitions/cpu" },
{ "$ref": "#/definitions/network" },
{ "$ref": "#/definitions/disk" },
{ "$ref": "#/definitions/window" }
]
}
]
}
First, we require that any instance MUST adhere to base which declares _ and name as required properties. Additionally, we declare a children array property that requires all items also match this schema (giving us a recursive behavior). This doesn't really do much except that it allows us to declare these things in one place instead of having to declare them in the other three definitions.
(Note that we don't declare _ in the properties list. This means that any value will pass for this portion of the schema. We clean it up in the next part. If you want to ensure that future components are declared with strings, then you can add a "type": "string" requirement to that property, but I don't feel it's necessary unless others are authoring those components.)
Second, we declare each of our specific types as separate definitions, using the const keyword to isolate the one we want. This construct is analogous to a switch (or case) statement. If the instance doesn't match one of these explicit options, it fails. If it's missing one of the required base properties, it fails.
This will get you where you want to be.
To take it further, there are two more things you can do:
Add required to the other definitions to say that the specific properties are also required (e.g. freq_Unit for the cpu definition).
Declare each of the definitions in separate files. This would allow you to add a new definition by simply adding a new file and referencing it in the main schema. In my opinion, it's a bit cleaner. Some people prefer to have it all in one file, though.

JSON schema for payloads accepted vs objects returned

I'm fleshing out schemas for a RESTful web service, and I'm a bit stumped on one small thing. Imagine if I have the following schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"urn": {
"type": "string"
}
}
}
Since the URN is generated by my service, I don't want to accept it in the client request. So urn is not included in the required array. However, it IS required in the response, so I can't use this schema to validate the response my service gives. I'd prefer not to have to use two different schemas and have to keep them in sync.
Is there a way to use a single schema to strictly model both cases? Or, if I need to use two schemas, is there a way to reference a common structural schema and just override the required field from my request and response schemas?
This is a known problem and there is no good way to handle it.
The only way to keep it to one schema is to not include the server generated properties in the required array and do additional checks on the server side to validate those properties.
No, there is no way to override a schema keyword. JSON Schema keywords always adds constraints to the set. You need to start with the common schema and extend from there using allOf.
Here is an example of the kind of thing you will need to do.
Creation Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/create-my-schema",
"type": "object",
"required": ["name"]
"properties": {
"name": {
"type": "string"
}
}
}
Full Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/my-schema",
"allOf": [{ "$ref": "http://example.com/create-my-schema" }],
"required": ["urn"],
"properties": {
"urn": {
"type": "string"
}
}
}
If you don't care about the human readability of the schemas, this approach is fine. Otherwise, some people have opted to dynamically build schemas on the server-side so the resulting schemas may have duplication, but the code doesn't.
You can use dynamic schema with the use of "oneOf"
{
"type" : "object",
"required" : ["name"],
"properties" : {
"name" : {
"oneOf" : [{
"$ref" : "#/definitions/withURN"
}, {
"$ref" : "#/definitions/withoutURN"
}
]
}
},
"definitions" : {
"withURN" : {
"properties" : {
"name" : {
"type" : "string"
},
"urn" : {
"type" : "string"
}
}
},
"withoutURN" : {
"properties" : {
"name" : {
"type" : "string"
}
}
}
}
}
for some example have a look: http://json-schema.org/example2.html
also this discussion thread: How to use dependencies in JSON schema (draft-04)

JSON schema draft4 VS JSON schema draft3

What are the features present in the schema draft 4 that are not in the JSON schema draft 3 produced by IETF ?
From the change logs:
New keywords
anyOf (match at least one schema in the schema array),
allOf (match all schemas in the schema array),
oneOf (match exactly one schema in the schema array),
not (do not match the schema),
multipleOf (replaces divisibleBy),
minProperties and maxProperties (the minimum and maximum number of members in an object instance),
definitions (standardized container for inlined subschemas).
Removed:
disallow
extends
divisbleBy
Changed in functionality:
Type
When the value is an array, schemas are no longer allowed as elements. Also, the array must have at least one element.
Before
{
"type": [ "string", { "other": "schema" } ]
}
Now
{
"anyOf": [
{ "type": "string" },
{ "other": "schema" }
]
}
Required
Before, it was an attribute of subschemas in properties. It is now a first level keyword playing the same role, and has a string array as an argument.
Before
{
"properties": {
"p": {
"type": "string",
"required": true
},
"q": {
"type": "string",
"required": true
}
}
}
Now
{
"properties": {
"p": { "type": "string" },
"q": { "type": "string" }
},
"required": [ "p", "q" ]
}
Dependencies
A single string in a property dependency is no longer allowed, only arrays are allowed
Before
{
"dependencies": { "a": "b" }
}
Now
{
"dependencies": { "a": [ "b" ] }
}
If you're interested in a deep dive, you can review a diff between the two drafts on the IETF site.
However, if you're looking for a simpler summary of changes, Geraint Luff and Francis Galiegue created a changelog page on the project's github wiki that lists the changes, additions, and removals.