JSON schema without "properties" keyword - json

Vendor send me a json schema. Please look at this:
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"type" : "object",
"definitions" : {
...
},
"oneOf" : [{
"$ref" : "#/definitions/commons/strings/text"
}, {
"$ref" : "#/definitions/dto/scriptStep"
}, {
"$ref" : "#/definitions/dto/callResult"
}
]
}
There is no "properties" keyword (but by the way there is very large "definitions" part). Does it mean that schema actually descibes empty json object {}? Or does it mean that json could contain one of elements from "oneOf" array?

All JSON Schema keywords are constraints. For example, the empty schema {} means that any JSON is valid. A schema with just `{ "type": "object" } mean that any JSON object is valid. There are no constraints on what properties the object has.
However, that isn't what your vendor is expressing in this schema. The JSON doesn't only have to be valid against the "type": "object", but also against one of the three schemas referenced in oneOf. Presumably, those schemas include a properties keyword.
This probably isn't the best designed schema, but it is valid.

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?

Json schema object property must be the key of an object

I'm currently writing a json schema and I was wondering if someone knows an answer to my problem. Can I ensure that an object's value equals the key of an object somewhere in the JSON. Given the following JSON:
{
"defaultConfig" : "config1",
"configs" : {
"config0" : {...},
"config1" : {...},
"config2" : {...}
}
}
Can I validate that the content of "defaultConfig" must be one of the keys of the properties of "configs" (e.g. "config0", "config1", "config2")? I can't use enums in this case, as the config names are not known beforehand?
Edit: Here's the schema I have so far:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties" : {
"defaultConfig" : {
"type" : "string"
},
"configs" : {
"type" : "object",
"patternProperties": {
"." : {"type" : "object"}
}
}
}
}
No, there is nothing in JSON Schema that allows a keyword to reference a different part of the data instance in that way.
However, the latest version of the specification allows extensions via the $vocabulary keyword, so if you are so inclined, you could write your own keyword that did what you needed.

How should a json-schema (draft7) implementation resolve `$ref`s defined in unknown keywords?

JSON-Schema-Test-Suite defines schemas such as this, and I assume they are valid:
{
"tilda~field": {"type": "integer"},
"slash/field": {"type": "integer"},
"percent%field": {"type": "integer"},
"properties": {
"tilda": {"$ref": "#/tilda~0field"},
"slash": {"$ref": "#/slash~1field"},
"percent": {"$ref": "#/percent%25field"}
}
}
Take this example below:
{
"$id": "http://example.com/root.json",
"definitions": {
"A": { "type": "integer" }
},
"properties": {
"$id": {
"type": "string"
},
"attributes": {
"$ref": "#/tilda~0field/slash~1field/$id"
}
},
"tilda~field": {
"$id": "t/inner.json",
"slash/field": {
"$id": {
"$id": "test/b",
"$ref": "document.json"
}
}
}
}
Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?
http://example.com/root.json/document.json
http://example.com/t/document.json
http://example.com/t/test/document.json
Which of the $ids in #/tilda~0field must be considered as baseURI for the $ref in question and why.
$refs are not resolved within unknown keywords because $ref and $id only apply inside schemas. Let's look at an example to see what I mean by this.
{
"$id": "http://example.com/foo",
"type": "object",
"properties": {
"aaa": {
"const": { "$ref": "#/definitions/bbb" }
},
"bbb": { "$ref": "#/definitions/bbb" }
},
"ccc": { "$ref": "#/definitions/bbb" },
"definitions": {
"bbb": { "type": "string" }
}
}
The document as a whole is a schema, so /$id is understood by JSON Schema.
The properties keyword is defined as an object whose values are schemas. Therefore, the value at /properties/bbb is a schema and /properties/bbb/$ref is understood by JSON Schema.
The value of the const keyword is unconstrained. The value at /properties/aaa/const may look like a schema, but it's just a plain JSON object. Therefore /properties/aaa/const/$ref is not understood by JSON Schema.
The value at /ccc is not a JSON Schema keyword, so it's value is not constrained and not a schema. Therefore, the $id and $ref keywords are not understood by JSON Schema.
That's how it works now. When you go back to older drafts (draft-05 iirc), it's a little different. Before then, $ref was defined in a separate specification called JSON Reference. JSON Schema extended JSON Reference. Therefore, the semantics of $ref applied everywhere it appeared in a JSON Schema.
EDIT:
What happens when a $ref inside a known keyword references a schema deep inside an unknown keyword. for example, what if #/properties/bbb referenced #/ccc?
That's a really good question. Referencing #/ccc should be an error because #/ccc is not a schema and $ref only allows you to reference a schema.
I just saw your question on the JSON Schema site in an issue. I'll post here what I posted there as well. However, also look at the edit.
Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?
I think Section 8.2 gives the answer: "A subschema's "$id" is resolved against the base URI of its parent schema." This means that it will be http://example.com/t/test/document.json.
Which of the $ids in #/tilda~0field must be considered as baseURI for the $ref in question and why.
The base URI for this is the $id at the root, re-routed by the $id in tilda~field.
Start with http://example.com/root.json.
Change folders to t and use file inner.json.
Change folders to test (inside t) and use file document.json.
EDIT
Having a look at #customcommander's reply and realizing that the value in tilde~field isn't processed as a schema, I'd like to say that the #ref wouldn't be processed at all. It's just a plain JSON string with no inherent meaning.
Are you sure your second schema is valid though?
For example according to the JSON Schema Core specification, the $id property should be a string
If present, the value for this keyword MUST be a string
Therefore the following looks wrong to me:
"slash/field": {
"$id": {
"$id": "test/b",
"$ref": "document.json"
}
}
Then I think that your first $ref isn't correct either:
"attributes": {
"$ref": "#/tilda~0field/slash~1field/$id"
}
It should probably read:
"attributes": {
"$ref": "#/tilda~0field/slash~1field"
}
The same specification document also says this about $id and $ref:
Cf this example
The "$id" keyword defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.
Or as Ajv simply puts it:
$ref is resolved as the uri-reference using schema $id as the base URI […].
Given the current state of your schema, I can only approximate the answer to your question but the ref would probably resolve to something like t/inner.json#document.json

Automatic `$schema` support in JSON schema?

I want to describe this JSON:
{
"key1": {},
"key2": {}
}
so I created this JSON schema:
{
"type": "object",
"patternProperties": {
".+": {
"type": "object"
}
}
}
The problem is that when I add a $schema link to the JSON, it's not valid:
First, it seems strange that $schema would need any kind of special treatment but even if I try this:
{
"type": "object",
"properties": {
"$schema": {
"type": "string"
}
},
"patternProperties": {
".+": {
"type": "object"
}
}
}
it's not fixed:
I'm browsing a couple of schemas at http://schemastore.org/json/ and they don't seem to have any special treatment of $schema. How does it work?
The $schema keyword is used to declare that a JSON fragment is actually a piece of JSON Schema.
But it's not used in your JSON when it's not a schema, i.e. it is not used in your JSON data.
You then use a validator to match the schema against the JSON data. For exmple you can use this validator. In the left you specify the schema in the right you specify JSON data (without any reference or link to the schema, you don't use the $schema keyword in the right side)
The $schema keyword specifies which version of the JSON Schema standard the schema applies to (again the JSON schema, not the JSON data). Most of the time is:
"$schema": "http://json-schema.org/draft-04/schema#"
More info here
The accepted answer is correct, but here is the workaround you need.
{
"type": "object",
"properties": {
"$schema": {
"type": "string"
}
},
"additionalProperties": {
"type": "object"
}
}
additionalProperites applies only to properties that are defined in properties. patternProperties, on the other hand, applies to any property that it matches. The way you wrote it with patternProperties means that "$schema" must be a string and it must be an object. Since those two things can never both be true, "$schema" will never validate with any value.

How to validate string and number using json schema

I would like to validate a schema based on either its maximum/minimum (number) OR maximumLength/minimumLength (string).
I have a json form:
[
{
"key":"foo",
"title":"Test",
"type":"string"
}
]
and a json schema:
{
"type": "object",
"properties": {
"foo": {
"type": ["number","string"],
"maxLength":2,
"minLength":0,
"minimum":3,
"maximum":10
}
}
}
and a json model:
{
"foo": "bar"
}
Why does this example not work with validation? The model I have is not validated to false. According to this document it is possible to have different types defined in an array, but how can we do validation based on min/max values?
Your schema is correct. The validator you are using doesn't work properly. Here is an alternative that uses anyOf instead.
{
"type": "object",
"properties": {
"foo": {
"anyOf": [
{ "$ref": "#/definitions/boundedNumber" }
{ "$ref": "#/definitions/boundedString" }
]
}
},
"definitions": {
"boundedString": {
"type": "string",
"maxLength": 2,
"minLength": 0
},
"boundedNumber": {
"type": "number",
"minimum": 3,
"maximum": 10
}
}
}
Although it is quite a bit longer, some would argue that this is actually easier to read/maintain because of the separation of the type specific keywords.
Your schema is validating JSON objects ("type":"object"). In addition, if they have a property with key "foo", its value must be either a number between 3 an 10, or a string of maximum length 2.
Valid objects according to your schema:
{"foo":6}
{"foo":"as"}
Invalid objects:
{"foo":60}
{"foo":"asereje"}
If you want to validate arrays you must define your parent object as an array and use items tag to specify the schema for the array items, for instance:
{
"type" : "array",
"items" : {
"type" : "object",
"properties" : {
"foo" : {
"type" : ["number", "string"],
"maxLength" : 2,
"minLength" : 0,
"minimum" : 3,
"maximum" : 10
}
}
}
}
The schema above would validate the following JSON array:
[{
"foo" : 6
}, {
"foo" : "as"
}
]
John the issue is the type "type" : ["number", "string"]
Angular Schema Form is generating fields from the combined JSON Schema and the UI Schema (form), when the field type is defined it knows which type to validate against, when there are multiple types it doesn't know which part of the spec to base the form field against, so it falls back to a textbox and does not add the appropriate validation requirements for string alone.
To achieve your desired outcome you would need to tell it which field type you wish to use. There is a bug in the 0.8.x versions where it does not validate based on the type set in the UI schema if it cannot determine the type in the data schema, I believe that is fixed in the latest development branch. If not if there is an issue raised in Git, I would prioritise it.