Given the following JSON object, how can I build json schema? Product1, Product2 and Product3 are dynamic "keys" and I could have many more like that, but each of them will have the same "value" object with required keys as packageId1, packageId2, packageId3 and their corresponding values as strings.
{
"Product1": {
"packageId1": "basicpackage",
"packageId2": "basicpackage",
"packageId3": "basicpackage"
},
"Product2": {
"packageId1": "newpackage",
"packageId2": "newpackage",
"packageId3": "newpackage"
},
"Product3": {
"packageId1": "thirdpackage",
"packageId2": "thirdpackage",
"packageId3": "thirdpackage"
}
}
I think I figured how to do it. In case anyone is interested, I am answering my own question. Also, I welcome better suggestions.
{
"title": "JSON Schema for Fulfillment Config",
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"patternProperties": {
".{1,}": {
"type": "object",
"properties": {
"packageId1": { "type": "string" },
"packageId2": { "type": "string" },
"packageId3": { "type": "string" }
}
}
}
}
Related
I want to create several json schemas for different scenarios.
For scenario 1 I would like to specify that:
a) The property "draftenabled" must have the value true.
b) the property "draftenabled" does exist.
I have checked this post
Validating Mandatory String values in JSON Schema
and tried the following
I tried to validate this json
{
"$schema": "./test-schema.json",
"draftenabled": false,
"prefix": "hugo"
}
with this schema test-schema.json that I had created in Visual Studio Code.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"$schema": {
"type": "string"
},
"draftenabled": {
"type": "boolean"
},
"prefix": {
"type": "string"
}
},
"additionalItems": false,
"contains": {
"properties": {
"draftenabled": {
"const": true
}
},
"required": [
"draftenabled"
]
}
}
I would have expected an error since the value for draftenabled is false rather than true.
It looks like there is some confusion around how the keywords apply to instances (data) of different types.
properties only applies to objects
additionalItems and contains only apply to arrays
Since your instance is an object, additionalItems and contains will be ignored.
Based on your description of what you want, I would do something like the following:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"properties": {
"$schema": {
"type": "string"
},
"draftenabled": {
"const": "true"
},
"prefix": {
"type": "string"
}
},
"required": [
"draftenabled"
]
}
This moves the definitions you have in the contains into the main schema. You got that bit right, just in the wrong place.
You also mention that this is a "scenario 1." If there are other scenarios, I suggest creating schemas like this for each scenario then wrapping all of them together in a oneOf or anyOf:
{
"oneOf": [
{ <scenario 1> },
{ <scenario 2> },
...
]
}
I am attempting to replicate the following Json Schema example, by defining the schema in code using Newtonsoft.Json.Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"address": {
"type": "object",
"properties": {
"street_address": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" }
},
"required": ["street_address", "city", "state"]
}
},
"type": "object",
"properties": {
"billing_address": { "$ref": "#/definitions/address" },
"shipping_address": { "$ref": "#/definitions/address" }
}
This is as close as I've got so far. (Example is in F# but might just as well be in C#.)
Code:
open Newtonsoft.Json.Schema
open Newtonsoft.Json.Linq
let makeSchema =
let addressSchema = JSchema()
addressSchema.Properties.Add("street_address", JSchema(Type = Nullable(JSchemaType.String)))
addressSchema.Properties.Add("city", JSchema(Type = Nullable(JSchemaType.String)))
addressSchema.Properties.Add("state", JSchema(Type = Nullable(JSchemaType.String)))
addressSchema.Required.Add "street_address"
addressSchema.Required.Add "city"
addressSchema.Required.Add "state"
let schema = JSchema()
schema.Properties.Add("billing_address", addressSchema)
schema.Properties.Add("shipping_address", addressSchema)
schema
Output:
{
"properties": {
"billing_address": {
"properties": {
"street_address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"street_address",
"city",
"state"
]
},
"shipping_address": {
"$ref": "#/properties/billing_address"
}
}
}
As you can see, only one of the two addresses is defined using a reference to another schema, and the address schema is in "properties" rather than "definitions". What's the trick to defining a schema in "definitions" and referencing it elsewhere?
Hackfest! :-)
According to the source code, JSON.NET Schema just doesn't write a definitions property, end of story. So it's all hopeless... Almost.
It does use the definitions property in another place, however. Namely - when generating schema from a type. During that process, it creates a JObject, pushes all schemas into it, and then adds that object to JSchema.ExtensionData under the definitions key. And when referencing a schema from another place, the schema writer will respect that definitions object, if present, thus making the whole thing work together.
So, armed with this knowledge, we can hack our way into it:
let makeSchema =
let addressSchema = JSchema()
...
let definitions = JObject() :> JToken
definitions.["address"] <- addressSchema |> JSchema.op_Implicit
let schema = JSchema()
schema.ExtensionData.["definitions"] <- definitions
schema.Properties.Add("billing_address", addressSchema)
schema.Properties.Add("shipping_address", addressSchema)
schema
And voila! The resulting schema now has a definitions object, just as the sacred texts tell us it should:
{
"definitions": {
"address": {
"properties": {
"street_address": {
"type": "string"
},
"city": {
"type": "string"
},
"state": {
"type": "string"
}
},
"required": [
"street_address",
"city",
"state"
]
}
},
"properties": {
"billing_address": {
"$ref": "#/definitions/address"
},
"shipping_address": {
"$ref": "#/definitions/address"
}
}
}
A few notes:
The definitions name is not special from the JSON.NET's point of view. If you change the line schema.ExtensionData.["definitions"] to something different, say schema.ExtensionData.["xyz"], it will still work, with references all pointing to "#/xyz/address".
This whole mechanism, obviously, is a hack Apparently not, according to James Netwon-King. The key insight seems to be that the JsonSchemaWriter will be able to lookup any previous mentions of schemas and use references to them in other places. This allows one to shove schemas wherever one likes and expect them to be referenced.
That op_Implicit call in there is necessary. JSchema is not a subtype of JToken, so you can't just jam it into definitions.["address"] like that, you have to convert it to JToken first. Fortunately, there is an implicit cast operator defined for that. Unfortunately, it's not straightforward, there seems to be some magic going on. This happens transparently in C# (because, you know, there is not enough confusion as it is), but in F# you have to call it explicitly.
Consider the following JSON :
{
"1234abcd" : {
"model" : "civic"
"made" : "toyota"
"year" : "2014"
}
}
consider another JSON :
{
"efgh56789" : {
"model" : "civic"
"made" : "toyota"
"year" : "2014"
}
}
the outermost alphanumeric key will vary and required, if the key was fixed; let's say "identifier" then the schema was straightforward, however since the key-name is variable, we have to use patternProperties, how can I come up with a schema that captures these requirement for the outermost key:
property name (key) is variable
required
alphanumeric lowercase
using json-schema : https://github.com/ruby-json-schema/json-schema in ruby.
The best you can do to require properties when those properties are variable is to use minProperties and maxProperties. If you want to say there must be one and only one of these alphanumeric keys in your object, you can use the following schema. If you want to say there has to be at least one, you could just leave out maxProperties.
{
"type": "object",
"patternProperties": {
"^[a-z0-9]+$": {
"type": "object",
"properties": {
"model": { "type": "string" },
"make": { "type": "string" },
"year": { "type": "string" }
},
"required": ["model", "make", "year"]
}
},
"additionalProperties": false,
"maxProperties": 1,
"minProperties": 1
}
You may have to change the regular expression to fit your valid keys:
{
"patternProperties": {
"^[a-zA-Z0-9]*$":{
"properties": {
"model":{"type":"string"},
"made":{"type":"string"},
"year":{"type":"string"}
}
}
},
"additionalProperties":false
}
I have the following simple JSON schema that does the regular expression match based on the content field of my data:
{
"$schema":"http://json-schema.org/schema#",
"allOf":[
{
"properties":{
"content":{
"pattern":"some_regex"
}
}
}
}
It successfully matches the following data:
{
"content": "some_regex"
}
Now lets say I want to add a list of UUIDs to ignore to my data:
{
"content": "some_regex",
"ignoreIds" ["123", "456"]
}
The problem arises when I want to modify my schema not to match when a given value is present in the list of ignoreIds:
Here is my failed attempt:
{
"$schema": "http://json-schema.org/schema#",
"allOf": [{
"properties": {
"content": {
"pattern": "some_regex"
}
}
}, {
"properties": {
"ignoreIds": {
"not": {
// how do I say 'do not match if "123" is in the ignoreIds array'????
}
}
}
}]
}
Any help will be appreciated!
your JSON schema for the ignoreIds has to be:
"ignoreIds": {
"type": "array",
"items": {
"type": "integer",
"not": {
"enum": [131, 132, whatever numbers you want]
}
}
}
which says
any value in the array ignoreIds matching the not-enum will make the
json invalid
This works of course for an array of strings also:
"ignoreIds": {
"type": "array",
"items": {
"type": "string",
"not": {
"enum": ["131", "132"]
}
}
}
Tested with JSON Schema Lint
In my json schema file i'm trying to force a reference property, $ref onto the user. However, the following does not work
-- sampleSchema.json --
{
"definitions": {
"items": {
"type": "object",
"properties": {
"ref": {
"type": "string"
}
}
}
},
"properties": {
"items" : {
"$ref": "#/definitions/items"
}
}
}
The desired output is this where the user must provide a reference path.
-- whatever.json --
{
"$schema" : "sampleSchema.json?reload",
"items": {
"$ref": "/myEntityReferenceOfChoice"
}
}
In in schema file if i leave the $ in , then it doesn't work. If i take it out for just 'ref' it does. Can i force the user to supply a $ref?
Im using Visual Studio 2013..