Why are booleans valid JSON schemas? - json

I'm looking at JSON schema's meta schemas and according to the Core/Validation Dialect meta-schema the JSON true and false are valid JSON schemas. What is the point of this?
You can see that they validate properly here.

It's true that a boolean schema, in its entirety, is not terribly useful, except perhaps as a placeholder ("in the future, we will have a more defined data structure; in the meantime, all values are acceptable"). But schemas can also contain schemas, and then we can start to express more meaningful things.
Consider describing data thusly:
the top level of the data must be an object.
the object must include the properties "alpha" and "beta".
the value of "alpha" must be a string.
the value of "beta" can be anything.
the property "gamma" may exist, and its value can be anything.
the property "epsilon" must not be present.
if there any other properties present, they must be numbers.
We would define the JSON schema like this:
{
"type": "object",
"required": ["alpha", "beta"],
"properties": {
"alpha": {
"type": "string"
},
"beta": true,
"gamma": true,
"epsilon": false,
},
"additionalProperties": {
"type": "number"
}
}
Now, as you can see, under the "properties" and "additionalProperties" keywords we have several subschemas. Some of the subschemas contain more keywords ("type" in this case), but some of the subschemas are just plain old booleans. They're conveying something of meaning: "this condition is always valid" or "this condition is always invalid".

Related

For JSON schemas, can the "type" keyword be missing if "pattern" keyword is set?

For JSON schemas, can you have the keyword "pattern" set but not have the keyword "type" set to anything? Concern is whether I need to correct existing schemas that do this like the following:
"ExampleType": {
"description": "blah blah",
"type": "array",
"items": {
"pattern": "sometext/ExampleType:[^:/]+:[0-9]*$"
}
}
I checked this here JSON validator and it can work however this would allow any non-string value so it will not care if a non-string value matches the pattern or not. For instance, you could have
{
"ExampleType" : ["sometext/ExampleType:try:1", "sometext/ExampleType:try:2", 5]
}
and it would pass. If the number 5 is put in quotes, then it would fail. So bottom line is that you should always specify the type and it will default to any type if not specified.

Json Schema, take into account unspecified properties

Is there is any ways to get heads ups about properties which are not described by schema into the standard. For example this schema:
{
"description": "foo and bar",
"type": "object",
"properties": {
"foo": {
"type": "number"
},
"bar": {
"type": "string",
"enum": [
"a",
"b",
"c"
]
}
}
}
Will pass this JSON:
{
"foo": 12345,
"bar": "a",
"baz": 12312
}
Although it has baz property which is not the part of schema.
UPD: As of now I'm using tv4 library.
Option 1: additionalProperties in the schema
If you want to explicitly constrained to the properties listed in a particular properties definition, then you can use additionalProperties: false. This will restrict data to only using properties defined in the nearby properties entry - in this case, "foo" and "bar".
However, use of additionalProperties impacts schema extension. If you (or someone else) extends this schema later (using allOf/$ref), then the data will still be subject to this schema - so will only be allowed to use "foo" and "bar", regardless of definitions elsewhere.
Option 2: banUnknownProperties flag in tv4
If the kind of complete lock-down is not desired, then you can use the banUnknownProperties flag in tv4 (docs). Basically, after validation, any properties that were not accounted-for by any schemas are raised as errors.
It was designed for cases when extra properties (including future variations/extensions) are theoretically allowed in the data format, but you want (for testing/warning purposes) to be alerted when extra properties show up where you're not expecting them.

JSON Schema regarding use of $ref

I understand that $ref takes a URI to a json schema to use but where does $ref : "#" point to?
Does it just mean use the current schema for this block level? Or does it mean to use the root level schema defined in the root level id?
Thanks
EDIT:
So if I have:
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
}
Because it lacks an id field it will attempt to validate the instance items with the root schema first and then if that fails try to validate it with the schemaArray schema defined in the definitions schema, right?
So if I change it to:
"items": {
"id" : "#/items",
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
}
Then the first subschema in anyOf array will point to the items schema itself?
EDIT #2: Okay so if I had:
"items": {
"id" : "itemSchema",
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
}
and
"stringArray": {
"type": "array",
"items": { "$ref" : "itemSchema" },
"minItems": 1,
"uniqueItems": true
}
"stringArray"'s "items" field would be validated against the above "itemsSchema"?
Also does the second $ref in 'anyOf' work by going to the root and then traversing down the path till it hits that schema?
Thanks!
OK: each $ref is resolved into a full URI. Once that is done, all your questions are answered by asking the question: What schema would I end up with, if I simply fetched that URI? Where the $ref is, how it was loaded, all of that is irrelevant - it's entirely dependent on the resolved URI.
The library might take some shortcuts (like caching documents so they are only fetched once, or trusting one schema to "speak for" another), but those are all implementation details.
Response to original question:
# is not special: all values of $ref are resolved as URIs relative to the current document (or the closest value of "id", if there is one).
Therefore, if you haven't used "id", then # will point to the root of the schema document. If you fetched your schema from http://example.com/schema, then a {"$ref": "#"} anywhere inside that will resolve to http://example.com/schema#, which is the document itself.
It is different when you use "id", because it changes the "base" schema against which the $ref is resolved:
{
"type": "array",
"items": {
"id": "http://example.com/item-schema",
"type": "object",
"additionalProperties": {"$ref": "#"}
}
}
In that example, the $ref resolves to http://example.com/item-schema#. Now, if your JSON Schema setup trusts the schema it already has, then it can re-use the value from "items".
However, the point is there is nothing special about # - it just resolves to a URI like any other.
Response to EDIT 1:
Your first example is correct.
However, your second is unfortunately not. This is because of the way that fragments resolution works for URIs: one fragment completely replaces another. When you resolve the # against the "id" value of #/items, you don't end up with #/items again - you end up with #. So in your second example, the first entry in "anyOf" will still resolve to the root of the document, just as in the first example.
Response to EDIT 2:
Assuming the document is loaded from http://example.com/my-schema, the full URIs of your two $refs are:
http://example.com/itemSchema#
http://example.com/itemSchema#/definitions/schemaArray
For the first one, the library may use the schema it already has, but it might not - after all, looking at the URIs, http://example.com/my-schema might not be trusted to accurately represent http://example.com/itemSchema.
For the second one - that's not going to work, because the "itemSchema" doesn't have a "definitions" section, so that $ref won't resolve properly at all.

JSON validate extra parameter using schema

I want to validate a json input through json schema. The positive case works for intended objects and properties.
But I want to validate against extra objects, parameters which are not mentioned in the schema.
Basically fail the validation if garbage data detected in the json
If you want to only have a certain set of properties in JSON objects and refuse others:
ensure the properties you want have a matching schema in either properties and patternProperties,
define additionalProperties to false:
{
"type": "object",
"properties": { "p": {}, "q": {} },
"additionalProperties": false
}
will only allow for properties p and q to exist in object instances.

How can i define a single, unique Key-Valuepair in JsonSchema?

The Schema should allow only the following constellation: {"status":"nok"}.
The Key must always be "status" and the value should allow "ok","nok","inProgress"
No differen or additional objects,... should be allowed
I have tried this:
{
"description": "blabla",
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ok",
"inProgress",
"nok"
],
"required": true,
"additionalItems": false
}
},
"required": true,
"additionalProperties": false
}
This works, but this scheme allows that i can send the same key/value pair twice like {"status":"nok","status":"nok"}
I would be also happy, if it would work without this "object"-container that i'm using, because to reduce overhead.
Maybe someone knows a solution, thanks
There is a more fundamental issue with that input:
{"status":"nok","status":"nok"}
mainly: that input is not valid JSON. RFC 4627, section 2.2, explicitly states that "The names within an object SHOULD be unique". And in your case, they are not.
Which means the JSON parser you use can do whatever it wants to with such an input. Some JSON APIs will grab whatever value they come upon first, other parsers will grab the last value they read, others will even coalesce values -- none of this is illegal as per the RFC.
In essence: given such input, you cannot guarantee what the output of the JSON parser will be; and as such, you cannot guarantee JSON Schema validation of such an input either.