People have been working on various JSON schema implementations for quite some time now, with only mixed success. Even when the implementations are current, supported, and working, they are notable mostly for how little attention they've gathered and how little they are used.
One reason for this is that modeling the problem JSON schema means to solve -- validation -- on the existing XML model of shemas is not entirely in line with the design philosphy and real-world use of JSON itself. It's not simple, it requires a considerable toolchain, and ultimately it relies on additional documents (the schema files themselves) that are at least as complicated as the JSON objects they describe, if not more so. In short, XML is not 'jsonic' and neither is laying XML's approach to validation on top of JSON.
JPath provides a lightweight, flexible alternative to schema. It allows you, as a creator or consumer of JSON content, to quickly and easily validate your assumptions about the JSON you're working with. It's completely optional so it doesn't get in your way, and you can selectively check validation rules so deviations from the specification that you don't care about don't get in your way either. Validation rules written in JPath can accompany any JSON object, so any JSON response can be truly self-describing. Also, because of the flattened, straightforward nature of JPath expressions, even simply reading the expressions allows you to quickly makes sense of even complex, deeply-nested JSON constructs.
Let's start with an example. Given a typical JSON object:
{"foo":
{
"bar": 3.6,
"biz": {
"baz": "baz string",
"boffo": "boffo string"
},
"steps" : [
"steal underpants",
"???????",
"biiiiiig profit!"
]
}
}A small handful of JPath expressions can pretty well cover what you'd want to know about this object:
foo.isJSONObject()
foo.bar.isJSONObject()
foo.bar.biz.isJSONObject()
foo.bar.biz.baz.isJSONString()
foo.bar.biz.baz.size() > 0
foo.bar.biz.boffo.isJSONString()
foo.bar.biz.boffo=='boffo string'
foo.bar.steps.isJSONArray()
foo.bar.steps.size() == 3
And so on. All of these expressions, when run through JPath, will return a literal value of "true". If they don't, you know where your validation has failed.
The expressions that define a JSON resource can be included in the resource itself. Extending our previous example:
{"foo":
{
"bar": 3.6,
"biz": {
"baz": "baz string",
"boffo": "boffo string"
},
"steps" : [
"steal underpants",
"???????",
"biiiiiig profit!"
]
},
"meta" : [
"foo.isJSONObject()",
"foo.bar.isJSONObject()",
"foo.bar.biz.isJSONObject()",
"foo.bar.biz.baz.isJSONString()",
"foo.bar.biz.baz.size() > 0",
"foo.bar.biz.boffo.isJSONString()",
"foo.bar.biz.boffo=='boffo string'",
"foo.bar.steps.isJSONArray()",
"foo.bar.steps.size() == 3"
]
}Here, a consumer needs only to iterate over the strings in the meta array and check that JPath evaluates to "true" for all.