JSON validate extra parameter using schema - json

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.

Related

JSON Schema object properties defined by enum

I'm attempting to reuse an enum in my JSON Schema to define the properties for an object.
I was wondering if the following is correct.
JSON Schema
{
"type": "object",
"propertyNames": {
"enum": ["Foo","Bar"]
},
"patternProperties": {
".*": {
"type": "number"
}
}
}
JSON Data
{
"Foo": 123,
"Bar": 456
}
The reason I ask is that I get inconsistent results from JSON Schema validation libraries. Some indicate the JSON validates, while others indicate the JSON is invalid.
p.s. if anyone is wondering "why" I'm trying to define the properties with an enum, it is because the enum is shared in various parts of my json schema. In some cases it is a constraint on a string, but I need the identical set of possible values both on those string properties and also on the object properties. As an enum I can maintain the set of possible values in one place.
Yes, that's a valid JSON Schema. You could also express it like this:
{
"type": "object",
"propertyNames": {
"enum": ["Foo","Bar"]
},
"additionalProperties": {
"type": "number"
}
}
It says "all property names must conform to this schema: (one of these values listed in the enum); also, all property values must conform to this schema: (must be numeric type)."
What errors do you get from the implementations that report this as invalid? Those implementations have a bug; would you consider reporting it to them?

Why are booleans valid JSON schemas?

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".

How to validate number of properties in JSON schema

I am trying to create a schema for a piece of JSON and have slimmed down an example of what I am trying to achieve.
I have the following JSON schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Set name",
"description": "The exmaple schema",
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"additionalProperties": false
}
The following JSON is classed as valid when compared to the schema:
{
"name": "W",
"name": "W"
}
I know that there should be a warning about the two fields having the same name, but is there a way to force the validation to fail if the above is submitted? I want it to only validate when there is only one occurrence of the field 'name'
This is outside of the responsibility of JSON Schema. JSON Schema is built on top of JSON. In JSON, the behavior of duplicate properties in an object is undefined. If you want to get warning about this you should run it through a separate validation step to ensure valid JSON before passing it to a JSON Schema validator.
There is a maxProperties constraint that can limit total number of properties in an object.
Though having data with duplicated properties is a tricky case as many json decoding implementions would ignore duplicate.
So your JSON schema validation lib would not even know duplicate existed.

How to validate structure of json using phpleague/json-guard

I'm using Laravel 5.4 for an api and have an endpoint that accepts JSON along the lines of:
{
"input": {
"owner": "name of owner",
"content": [
]
}
}
I want to get only the JSON inside input and ensure that it is valid, both structurally and based on the content.
Using http://json-guard.thephpleague.com and their basic example from the overview page, everything comes back as valid no matter what I change as the input so I assume I am using it wrong.
From their example I have constructed the following. It passes validation. The issue is that I cannot get it to fail.
routes file
Route::post('validate', 'TestController#validateJson');
TestController#validateJson
public function validateJson()
{
$dereferencer = \League\JsonReference\Dereferencer::draft4();
$schema = json_decode('{ "properties": { "id": { "type": "string", "format": "uri" } } }');
$data = json_decode('{ "id": "https://json-guard.dev/schema#" }');
$validator = new \League\JsonGuard\Validator($data, $schema);
if ($validator->fails()) {
return response($validator->errors());
}
return response('all ok');
}
I believe I might need to use the JSON Reference and define a custom schema, but until I can fully understand the example and get it to fail, I don't want to do anything more complicated.
everything comes back as valid no matter what I change as the input so I assume I am using it wrong.
It is hard to say exactly what the issue is without seeing an example of what input you tried. Since the example schema validates that id is a string with the uri format, it should fail when you provide a string that is not a valid URI. The following example will return a format error:
<?php
require __DIR__ . '/vendor/autoload.php';
$schema = json_decode('{ "properties": { "id": { "type": "string", "format": "uri" } } }');
$data = json_decode('{ "id": "hello world" }');
$validator = new \League\JsonGuard\Validator($data, $schema);
echo json_encode($validator->errors(), JSON_PRETTY_PRINT);
There are some parts of JSON Schema that are unintuitive and you might not expect to pass.
A constraint only validates if it applies to that type. If you don't pass an object validation will pass because the properties constraint only applies to objects:
$data = null;
var_dump((new \League\JsonGuard\Validator($data, $schema))->passes()); // true
To make non object inputs fail you need to specify "type": "object". Note that this will also happen with invalid JSON, since json_decode will return null when it fails.
Validation will also pass with an empty object:
$data = json_decode('{}');
var_dump((new \League\JsonGuard\Validator($data, $schema))->passes()); // true
To make the properties required you have to use the required keyword.
I want to get only the JSON inside input and ensure that it is valid, both structurally and based on the content.
This schema should work as a starting point:
{
"type": "object",
"properties": {
"input": {
"type": "object",
"properties": {
"owner": {
"type": "string",
"minLength": 1"
},
"content": {
"type": "array"
}
},
"required": ["owner", "content"],
"additionalProperties": false
}
},
"required": ["input"],
"additionalProperties": false
}
We are requiring that the input is an object, that it has an input property and no other properties, and that input is an object with the properties owner and content. The minLength rule on owner is to prevent an empty string from passing.
I believe I might need to use the JSON Reference and define a custom schema
You can write pretty complex schemas without using JSON Reference at all. It's just a way to reuse a schema without copy and pasting. For example, you might define a 'money' schema and use that for any dollar amounts in your API.
You definitely will need to write a custom schema. The schema replaces the Laravel validation rules you would write for each endpoint otherwise.

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.