Who Am I?
I ❤️ questions
ask them!
(After the talk or raise your hand during the talk)
6767"SiIiIx Severn"67"SiIiIx Severn"|
this_is_peak_comedy |
|
|---|---|
|
please_help |
{
"this_is_peak_comedy": 67,
"please_help": "SiIiIx Severn"
}Java Script Object Notation
{
"this_is_peak_comedy": 67,
"please_help": "SiIiIx Severn"
}JSON
JSON
JSON
(if you are my older brother)
{
"$schema": "http://json-schema.org/v1-coming-soon-🎉🎉🎉/schema#",
"title": "My Cool JSON Schema",
"type": "object",
"properties": {
"what": {
"type": "string"
},
"is": {
"type": "number"
},
"a": {
"enum": ["json", "schema"]
},
},
"additionalProperties": false,
"required": [
"version"
]
}{"type": "number"}{"type": "number"}67✅
{"type": "number"}67✅
"SiIiIx Severn"❌
{"type": "string"}67✅
"SiIiIx Severn"❌
{
"this_is_peak_comedy": 67,
"please_help": "SiIiIx Severn"
}{
"type": "object",
"properties": {
"this_is_peak_comedy": {"type": "number"},
"please_help": {"type": "string"}
}
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "My Cool JSON Schema",
"type": "object",
"properties": {
"what": {
"type": "string"
},
"is": {
"type": "number"
},
"a": {
"enum": ["json", "schema"]
},
},
"additionalProperties": false,
"required": [
"version"
]
}{
"what": "foo",
"is": 5,
"a": "json"
}{well}
{structured}
{data}
{yaaay}
{well}
{structured}
{data}
{yaaay}
2 YEARS
{Go Chaff}
{
"type": "number"
}4.5Generate
{
"type": "integer"
}5Generate
{
"type": "integer",
"minimum": 10
}10Generate
{
"type": "integer",
"exclusiveMinimum": 10
}11Generate
ᴇᴀsʏ
{
"type": "integer",
"multipleOf": 7,
"exclusiveMinimum": 10
}14Generate
:(
{
"type": "number",
"multipleOf": 0.00324634,
"exclusiveMinimum": 0.00634,
"maximum": 0.086785345
}🫠Generate
maybe strings will be easier
{
"type": "string"
}Generate
"foo"{
"type": "string",
"format": "time"
}Generate
"???"(Annotation as of latest draft)
{
"type": "string",
"format": "time"
}Generate
"03:46:13+00:00"{
"type": "string",
"pattern": "\w+"
}oh no...
{
"type": "string",
"pattern": "\w+\d{0,1}"
}oh no... please no...
{
"type": "string",
"pattern": "^(?=.{1,256})(?=.{1,64}@.{1,255}$)(?:(?![_.-])[a-zA-Z0-9._%+-]{1,64}(?:(?:(?<!\\)[.,;:])?(?=.{0,64})[a-zA-Z0-9._%+-]{0,64})?@(?:(?!-)[a-zA-Z0-9-]{1,63}(?:(?:(?<!\\)[.,;:])?(?=.{0,255})[a-zA-Z0-9-]{0,63})?\.?)+(?:(?!-)[a-zA-Z]{2,})?|(?:[a-zA-Z0-9-]{1,63}\.[a-zA-Z]{2,}))(?=.{1,256})(?=.{1,64}@.{1,255}$)(?:(?![_.-])[a-zA-Z0-9._%+-]{1,64}(?:(?:(?<!\\)[.,;:])?(?=.{0,64})[a-zA-Z0-9._%+-]{0,64})?@(?:(?!-)[a-zA-Z0-9-]{1,63}(?:(?:(?<!\\)[.,;:])?(?=.{0,255})[a-zA-Z0-9-]{0,63})?\.?)+(?:(?!-)[a-zA-Z]{2,})?|(?:[a-zA-Z0-9-]{1,63}\.[a-zA-Z]{2,}))(?=.{1,256})(?=.{1,64}@.{1,255}$)(?:(?![_.-])[a-zA-Z0-9._%+-]{1,64}(?:(?:(?<!\\)[.,;:])?(?=.{0,64})[a-zA-Z0-9._%+-]{0,64})?@(?:(?!-)[a-zA-Z0-9-]{1,63}(?:(?:(?<!\\)[.,;:])?(?=.{0,255})[a-zA-Z0-9-]{0,63})?\.?)+(?:(?!-)[a-zA-Z]{2,})?|(?:[a-zA-Z0-9-]{1,63}\.[a-zA-Z]{2,}))(?=.{1,256})(?=.{1,64}@.{1,255}$)(?:(?![_.-])[a-zA-Z0-9._%+-]{1,64}(?:(?:(?<!\\)[.,;:])?(?=.{0,64})[a-zA-Z0-9._%+-]{0,64})?@(?:(?!-)[a-zA-Z0-9-]{1,63}(?:(?:(?<!\\)[.,;:])?(?=.{0,255})[a-zA-Z0-9-]{0,63})?\.?)+(?:(?!-)[a-zA-Z]{2,})?|(?:[a-zA-Z0-9-]{1,63}\.[a-zA-Z]{2,}))$"
}😭
Json's first scheme
Scheme 1: Constraints easy one direction...
{
"type": "number",
"multipleOf": 0.5,
"minimum": 6
}5Is valid?
Scheme 1: Constraints easy one direction...
5{"type": "number"}{"multipleOf": 0.5}✅
{"minimum": 6}✅
✅
❌
Not Valid
Scheme 1: Constraints easy one direction... but not the other
???
{"type": "number"}{"multipleOf": 0.5}{"minimum": 6}???
¯\_(ツ)_/¯Anything!
Err... -1?
Err... -0.5?
Err 7 right?
Compiling "Generators" ahead of time
{
"type": "number",
"multipleOf": 0.5,
"minimum": 6
}Random number generator:
- Must Have number higher than 6
- Must only generate in increments of 0.5{
"type": "object",
"properties": {
"some_array": {
"type": "array",
"minItems": 5,
"items": {
"const": "test"
}
},
"some_string": {
"minLength": 5
}
}
}Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Scheme 1: Constraints easy one direction... but not the other
Scheme 1: Constraints easy one direction... but not the other
{
"allOf": [
{
"type": "string",
"minLength": 5
},
{
"format": "time"
}
]
}😱
How can we work around this?
anyOf
{
"anyOf": [
{"type": "string"},
{"type": "number"}
]
}anyOf
{
"anyOf": [
{"type": "string"},
{"type": "number"}
]
}"yay"✅
oneOf
{
"oneOf": [
{
"enum": ["foo", "baz"]
},
{
"enum": ["baz", "bar"]
}
]
}oneOf
{
"oneOf": [
{
"enum": ["foo", "baz"]
},
{
"enum": ["baz", "bar"]
}
]
}Generate
"baz"oneOf
{
"oneOf": [
{
"enum": ["foo", "baz"]
},
{
"enum": ["baz", "bar"]
}
]
}"baz"Validate
oneOf
{
"oneOf": [
{
"enum": ["foo", "baz"]
},
{
"enum": ["baz", "bar"]
}
]
}Generate
"foo"Repeat if not valid
(up to a limit)
allOf
{
"allOf": [
{
"minLength": "5"
},
{
"type": "string"
}
]
}allOf
"allOf": [
{
"minimumLength": "5"
},
{
"type": "string"
}
]
"type": "string",
"minimumLength": 5,
Merge
allOf
"allOf": [
{
"minimumLength": "5"
},
{
"type": "string"
}
]
"type": "string",
"minimumLength": 5,
Merge
Generate
"Heloooo"Easy right....?
allOf: Err what about this?
{
"allOf": [
{"type": "integer"},
{"multipleOf": 8},
{"multipleOf": 14},
{"minimum": 20},
{"exclusiveMinimum": 55},
{"maximum": 600}
]
}allOf: Custom Merge algorithm
{
"exclusiveMinimum" : 55,
"maximum" : 600,
"minimum" : 20,
"multipleOf" : 112,
"type" : "integer"
}Make the most restrictive intersection of all given nodes
Ok so we are done right... right?
{
"$ref": "https://despair.com/hahah.json#/nope"
}Is that URL
IS THAT A URL
Scheme 3: $refusing to accept defeat
{
"$schema": "http://json-schema.org/draft-9001/schema#",
"type": "object",
"properties": {
"who_would_be_silly_enough_to_make_a_json_schem_faker": {
"$ref": "#/$defs/me"
}
},
"$defs": {
"me": {
"properties": {
"pain": {"const": "owwww"},
"suffering": {"const": "ouchie"}
},
"required": ["pain", "suffering"]
}
}
}Scheme 3: $refusing to accept defeat
{
"$schema": "http://json-schema.org/draft-9001/schema#",
"type": "object",
"properties": {
"who_would_be_silly_enough_to_make_a_json_schem_faker": {
"$ref": "#/$defs/me"
}
},
"$defs": {
"me": {
"properties": {
"pain": {"const": "owwww"},
"suffering": {"const": "ouchie"}
},
"required": ["pain", "suffering"]
}
}
}Scheme 3: $refusing to accept defeat
{
"$schema": "http://json-schema.org/draft-9001/schema#",
"type": "object",
"properties": {
"who_would_be_silly_enough_to_make_a_json_schem_faker": {
"$ref": "#/$defs/me"
}
},
"$defs": {
"me": {
"properties": {
"pain": {"const": "owwww"},
"suffering": {"const": "ouchie"}
},
"required": ["pain", "suffering"]
}
}
}Scheme 3: $refusing to accept defeat
{
"$schema": "http://json-schema.org/draft-9001/schema#",
"type": "object",
"properties": {
"who_would_be_silly_enough_to_make_a_json_schem_faker": {
"$ref": "#/$defs/me"
}
},
"$defs": {
"me": {
"properties": {
"pain": {"const": "owwww"},
"suffering": {"const": "ouchie"}
},
"required": ["pain", "suffering"]
}
}
}Scheme 3: $refusing to accept defeat
| Reference | Generator |
|---|---|
| #/$defs/me/properties/suffering | ConstGenerator: "Oww" |
| #/$defs/me/properties/pain | ConstGenerator: "Suffering" |
| #/$defs/me | ObjectGenerator |
| #/properties/who_would_be_silly_enough_to_make_a_json_schem_faker | ReferenceGenerator: "#/$defs/me" |
| # | Root Generator |
Scheme 3: It's time to write a web crawler🕷️
{
"type": "object",
"properties": {
"who_would_be_silly_enough_to_make_a_json_schem_faker": {
"$ref": "http://www.example.com#/$defs/me"
}
}
}# http://www.example.com
{
"$defs": {
"me": {
"properties": {
"pain": {"const": "owwww"},
"suffering": {"const": "ouchie"}
}
"required": ["pain", "suffering"]
}
}
}Scheme 3: It's time to write a web crawler🕷️
| Reference | Generator |
|---|---|
| #/properties/who_would_be_silly_enough_to_make_a_json_schem_faker | ReferenceGenerator: "http://www.example.com#/$defs/me" |
| # | Root Generator |
| Reference | Generator |
|---|---|
| #/$defs/me/properties/suffering | ConstGenerator: "Oww" |
| #/$defs/me/properties/pain | ConstGenerator: "Suffering" |
| #/$defs/me | ObjectGenerator |
| # | Root Generator |
www.example.com
Root Document
Scheme 3: It's time to write a web crawler🕷️
| Reference | Generator |
|---|---|
| #/properties/who_would_be_silly_enough_to_make_a_json_schem_faker | ReferenceGenerator: "http://www.example.com#/$defs/me" |
| # | Root Generator |
| Reference | Generator |
|---|---|
| #/$defs/me/properties/suffering | ConstGenerator: "Oww" |
| #/$defs/me/properties/pain | ConstGenerator: "Suffering" |
| #/$defs/me | ObjectGenerator |
| # | Root Generator |
www.example.com
Root Document
Scheme 3: $ref...
{
"type": "object",
"properties": {
"value": { "type": "string" },
"next": { "$ref": "#/" }
}
}Scheme 3: $ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$ref$
{
"type": "object",
"properties": {
"value": { "type": "string" },
"next": { "$ref": "#/" }
}
}Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 0
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 1
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 2
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 3
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 4
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 5
Max Effort: 5
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 5
Max Effort: 5
¯\_(ツ)_/¯
Scheme 3: Circular References
an asside on complexity
Object Generator
"some_array"
Array Generator(Min Len: 5)
Constant Generator: "test"
String Generator (min len: 5)
"some_string"
Generation Effort: 5
Max Effort: 5
Return
Scheme 3: Circular References
However when we need to merge
{
"allOf": [
{"$ref": "#/someCircularRef"}
]
}Scheme 3: Circular References
However when we need to merge
{
"$id": "node",
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": "..."
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}Scheme 3: Circular References
However when we need to merge
{
"$id": "node",
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": {
"type": "object",
"properties": {
"value": { "type": "string" },
"next": "..."
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}Scheme 3: Circular References
If you have any idea how this might be resolvable please let me know! *
(Tell me I am silly!)
*(Currently in the process of looking into the approach used in https://github.com/udamir/allof-merge)It does not seem to cover enough edge cases * Currently looking at trying to reduce the the space into a SAT problem and finding a correct set of constraints to use
Please no more
Scheme 4: NOT
Scheme 4: NOT
My sanity
!
One Exclamation mark boi
Scheme 4: NOT
from a validators perspective
{
"not": {
"multipleOf": 5
}
}Scheme 4: NOT
from a validators perspective
{
"not": {
"multipleOf": 5
}
}Validate Against
Scheme 4: NOT
from a validators perspective
easy :)
{
"not": {
"multipleOf": 5
}
}Validate Against
Invert result :)
Scheme 4: NOT
{
"minimum": 45,
"exclusiveMaximum": 64,
"multipleOf": 7,
"not": {
"exclusiveMinimum": 48,
"maximum": 55,
"multipleOf": 14
}
}From a generators perspective.
Just find the number easy :)
Scheme 4: Do it all again... backwards
func resolveBoundsFloat64(metadata *parserMetadata,
minFieldName string,
maxFieldName string,
minPtr *float64, minExclusivePtr *float64,
maxPtr *float64, maxExclusivePtr *float64,
notMinPtr *float64, notMinExclusivePtr *float64,
notMaxPtr *float64, notMaxExclusivePtr *float64,
offsetIncrement float64,
) (*float64, *float64, *float64, *float64)Scheme 4: notMerging
Scheme 4: notMerging
{
"enum": [
"foo", "baz", "bar"
],
"not": {
"enum": ["baz", "bar"]
}
}Scheme 4: notMerging
{
"enum": [
"foo", "baz", "bar"
],
"not": {
"enum": ["baz", "bar"]
}
}{
"const": "foo"
}Simplifies to
Scheme 4: notMerging
{
"minimum": 45,
"exclusiveMaximum": 64,
"multipleOf": 7,
"not": {
"exclusiveMinimum": 48,
"maximum": 55,
"multipleOf": 14
}
}Scheme 4: notMerging
{
"minimum": 45,
"exclusiveMaximum": 64,
"multipleOf": 7,
"not": {
"exclusiveMinimum": 48,
"maximum": 55,
"multipleOf": 14
}
}{
"const": 63
}Simplifies to
Scheme 4: Not not
{
"not": {
"not": {
"not": {
"not": {
"not": {
"type": "object",
"required": ["children"]
}
}
}
}
}
}Scheme 4: Not not
{
"not": {
"not": {
"type": "object",
"required": ["children"]
}
}
}Scheme 4: Not not
{
"not": {
"not": {
"type": "object",
"required": ["children"]
}
}
}Is Equal To
{
"type": "object",
"required": ["children"]
}
Scheme 4: Not not
{
"not": {
"not": {
"not": {
"not": {
"not": {
"type": "object",
"required": ["children"]
}
}
}
}
}
}Merge alternating (excluding not)
using the allOf merge algorithm, leaving a single node and notNode
Scheme 4: not
Scheme 4: not
Still need to resolve merging for `if`, `then`, `else`, `oneOf`, `allOf`, `anyOf`
Anything else?
Anything else?
{
"mimimum": 20,
"maximum: 10
}Anything else?
{
"minimum": 20,
"maximum": 10
}wat?
Anything else?
{
"minimum": 20,
"maximum": 10
}Scheme 5: where logic breaks down...
{"mimimum": 20}{"maximum": 10}15Scheme 5: where logic breaks down...
✅
{"mimimum": 20}{"maximum": 10}15Scheme 5: where logic breaks down...
✅
{"mimimum": 20}{"maximum": 10}15Scheme 5: where logic breaks down...
✅
❌
Not valid
15Scheme 5: where logic breaks down...
for a generator
{
"mimimum": 20,
"maximum": 10
}Error? Null?
Scheme 5: where logic breaks down...
To really exemplify the point lets have a quiz
Note that for the purposes of this quiz an "Illogical schema" is one where traits of the schema invalidate each other. Or we could not pass in data other than an empty value to satisfy the schema.
If you have any questions about how keywords work ask me!
(If I have missed anything assume you need to match all the constraints given to have the schema validate)
Scheme 5: where logic breaks down...
Practice: Is the schema illogical?
{
"pattern": "\\d+\\w{2}",
"maxLength": 3
}Practice: Is the schema illogical?
{
"pattern": "\\d+\\w{2}",
"maxLength": 3
}Logical ✅
Matches at min a 3 char sequence
Matches up to 3 chars
Q1: Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.25,
"mimimum": 40,
}Q1: Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.25,
"mimimum": 40,
}Logical ✅
Q1: Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.25,
"mimimum": 40,
}Logical ✅
All integers are
multiples of 0.25
Q2 Is the schema illogical?
{
"type": "integer",
"const": 3.5
}Q2 Is the schema illogical?
{
"type": "integer",
"const": 3.5
}Illogical ❌
Q2 Is the schema illogical?
{
"type": "integer",
"const": 3.5
}Illogical ❌
Must always be 3.5... which is not a whole number
Q3 Is the schema illogical?
{
"type": "number",
"minimum": 10,
"maximum": 5
}Q3 Is the schema illogical?
{
"type": "number",
"minimum": 10,
"maximum": 5
}Illogical ❌
Q3 Is the schema illogical?
{
"type": "number",
"minimum": 10,
"maximum": 5
}Illogical ❌
Q4: Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"not": {
"minimum": 9999
}
}Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"not": {
"minimum": 9999
}
}Illogical ❌
Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"maximum": 9999
}Illogical ❌
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"not": {
"minimum": 9999
}
}Simplifies To
Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"maximum": 9999
}Illogical ❌
Smallest possible integer multiple 9999
Is the schema illogical?
{
"type": "integer",
"multipleOf": 0.9999,
"mimimum": 0,
"maximum": 9999
}Illogical ❌
Smallest possible integer multiple 9999
Not valid against
("exclusiveMaximim" would)
Q5: Is the schema illogical?
{
"type": "array",
"allOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Is the schema illogical?
Illogical ❌
{
"type": "array",
"allOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Is the schema illogical?
{
"type": "array",
"allOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Illogical ❌
Mutually exclusive
Q6 Is the schema illogical?
{
"type": "array",
"anyOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Is the schema illogical?
{
"type": "array",
"anyOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Logical ✅
Can Match
any of the
schemas!
Is the schema illogical?
{
"type": "array",
"oneOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Is the schema illogical?
{
"type": "array",
"oneOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Illogical ❌
Is the schema illogical?
{
"type": "array",
"oneOf": [
{
"items": {
"enum": [
"foo",
"baz"
]
},
},
{
"items": {
"const": "foo",
}
},
{
"items": {
"const": "baz"
}
}
]
}Illogical ❌
Will always match
more than one
Q7 Is the schema illogical?
{
"$ref": "#/$defs/node",
"$defs": {
"node": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"children": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/node"
}
},
},
"required": [
"children"
]
}
}
}Is the schema illogical?
{
"$ref": "#/$defs/node",
"$defs": {
"node": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"children": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/node"
}
},
},
"required": [
"children"
]
}
}
}Illogical ❌
Is the schema illogical?
{
"$ref": "#/$defs/node",
"$defs": {
"node": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"children": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/node"
}
},
},
"required": [
"children"
]
}
}
}Illogical ❌
Forces infinite
recursion
Is the schema illogical?
{
"$ref": "#/$defs/node",
"$defs": {
"node": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"children": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/$defs/node"
}
},
},
"required": [
"children"
]
}
}
}Illogical ❌
Forces infinite
recursion
Tie breaker
Scheme 5: Illogical Schemas
What we can do about this?
Scheme 5: Illogical Schemas
Scheme 5: Illogical Schemas
As we go forwards
There are a few other things:
if/then/else clauses are fairly difficult to resolve during merging and have a number of different bugs$dynamicReference, $depentantProperties, ect...
Why Bother using a JSON schema faker?
Testing
JSON Schema Faker
Testing
JSON Schema Faker
JSON Schema Validator
Testing
Generate
Validate
JSON Schema Faker
X100
JSON Schema Validator
Testing
Generate
Validate
JSON Schema Faker
X100
JSON Schema Validator (s)
Testing for differences by fuzzing
✅
✅
✅
❌
Exploring Your Schemas
{
"properties": {
"sometimes_schemas": {
"const": "can be very complex"
}
}
}{"sometimes_schemas":"can be very complex"}Having a JSON schema faker generate many samples can be a great way of understanding what a schema is looking for or find issues with
Test Mocks
The original use case was a need for high quality random data, something JSON schema is set to do really well as it already aims to cover the shape of pretty much any structured data format.
This is one of the main reasons for using json schema
{schema}
{data}
Generative Testing / Fuzzing
<Your API>🚨You have gone more than 30 minutes without talking about AI🚨
Why Not Use AI?
*
* For the problem:
"Generate random JSON to satisfy a given JSON schema"
You can use json schemas to force LLMs to generate valid json data For instance .txt are trying to solve this problem
Only speak with this JSON schema
Only speak with this JSON schema
{
"structured": "data",
"with": "purpose"
}- MCP
- Anything that really requires well structure data
Feed into
Why Not Use AI?
Bad Output
[More bugs to fix yaaay]
use a larger model ¯\_(ツ)_/¯?
Bad Output
Why Not Use AI?
100x faster
- Mascot design by @Iroshi_ CC0
- Most other Images CC0 Wikimedia commons
https://github.com/ryanolee/go-chaff
Bugs and PR's always appreciated :)