Json schema object property must be the key of an object - json

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.

Related

How can I make patternProperties take a specific format in JSON schema?

I have the following schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"additionalProperties": {
"type": "string"
}
}
I'm trying to make the key of additionalProperties conform to a URL, so it would validate the following:
{
"https://google.com": "google"
}
but not this:
{
"google": "website"
// ^^^^^^ this is not a url
}
How can I do this?
You can specify the format of property names with patternProperties, which takes a pattern just like the pattern keyword.
If you want to do something more complicated, you can use propertyNames, which takes a schema that the property name must validate against. That might be what you want here:
{
"propertyNames": {
"format": "iri"
},
"additionalProperties": {
.. schema for the property values themselves
}
}
reference: https://json-schema.org/understanding-json-schema/reference/object.html#property-names

JSON schema without "properties" keyword

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.

JSON schema for payloads accepted vs objects returned

I'm fleshing out schemas for a RESTful web service, and I'm a bit stumped on one small thing. Imagine if I have the following schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"urn": {
"type": "string"
}
}
}
Since the URN is generated by my service, I don't want to accept it in the client request. So urn is not included in the required array. However, it IS required in the response, so I can't use this schema to validate the response my service gives. I'd prefer not to have to use two different schemas and have to keep them in sync.
Is there a way to use a single schema to strictly model both cases? Or, if I need to use two schemas, is there a way to reference a common structural schema and just override the required field from my request and response schemas?
This is a known problem and there is no good way to handle it.
The only way to keep it to one schema is to not include the server generated properties in the required array and do additional checks on the server side to validate those properties.
No, there is no way to override a schema keyword. JSON Schema keywords always adds constraints to the set. You need to start with the common schema and extend from there using allOf.
Here is an example of the kind of thing you will need to do.
Creation Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/create-my-schema",
"type": "object",
"required": ["name"]
"properties": {
"name": {
"type": "string"
}
}
}
Full Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "http://example.com/my-schema",
"allOf": [{ "$ref": "http://example.com/create-my-schema" }],
"required": ["urn"],
"properties": {
"urn": {
"type": "string"
}
}
}
If you don't care about the human readability of the schemas, this approach is fine. Otherwise, some people have opted to dynamically build schemas on the server-side so the resulting schemas may have duplication, but the code doesn't.
You can use dynamic schema with the use of "oneOf"
{
"type" : "object",
"required" : ["name"],
"properties" : {
"name" : {
"oneOf" : [{
"$ref" : "#/definitions/withURN"
}, {
"$ref" : "#/definitions/withoutURN"
}
]
}
},
"definitions" : {
"withURN" : {
"properties" : {
"name" : {
"type" : "string"
},
"urn" : {
"type" : "string"
}
}
},
"withoutURN" : {
"properties" : {
"name" : {
"type" : "string"
}
}
}
}
}
for some example have a look: http://json-schema.org/example2.html
also this discussion thread: How to use dependencies in JSON schema (draft-04)

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.

JSON-Schema pattern repetition inside array

Is there a way to create a repetition pattern for elements inside array of a JSON Schema document. I would like to use it in order to validate query produced by a query builder tool.
the part of the schema i currently use is
"complexCondition": {
"anyOf": [
{
"title": "Simple condition, e.x. X==0",
"type": "string"
},
{
"type": "array",
"items": [
{
"$ref": "#/complexCondition"
},
{
"type": "string", "enum": ["AND","OR"]
},
{
"$ref": "#/complexCondition"
}
],
"additionalItems": false
}
]
}
This allows me correct validation of query "conditionA && conditionB && conditionC" as
[[conditionA,"AND",conditionB],"AND",conditionC]
However, I would like to be able and validate documents where query is stored as
[conditionA,"AND",conditionB,"AND",conditionC]
and this to achievable for any number of conditions.
In order to achieve what you intend to do you would need to define a rule for odd and even positions
in an array, which can not be done for arrays of any length with json-schema.
If your expected number of query conditions is not going to grow ad infinitum, you could hard-code the first n positions in items keyword:
"items":[{"$ref":"#/condition},{"$ref":"#/operator"},{"$ref":"#/condition},{"$ref":"#/operator"} ... etc.]
In this case you still have the problem that you could define a wrong condition ending in "operator".
Other option would be to make "oneOf" and build each posibility (this could be automated with a script, I guess you won't have expressions with 100 clauses...)
Anyway I find a bit strange to try to flatten a concept that is inherently recursive.
How would you store this ( (A OR B) OR (C AND B))?
So If you can still rethink your desired serialization schema format I would suggest you to make a recursive approach. Something like:
"predicate" : {
"type" : "array",
"items" : {
"$ref" : "#/clause"
}
}
"clause" : {
"type" : "array",
"items" : [{
"$ref" : "#/condition"
}
],
"additionalItems" : {
"type" : "array",
"items" : [{
"$ref" : "#/operator"
}, {
"$ref" : "#/clause"
}
]
}
}
The generated string is more ugly, but parsing it would be fairly easy with a simple recursive function:
Simple condition:
[["condition1"]]
Simple Clause:
[["condition1",["OR",["condition2"]]]
Adding a clause at the same level
[["condition1",["OR",["condition2"]],["OR",["condition3"]]]
Add a clause to a child level
[["condition1",["OR",["condition2"]],["OR",["condition3", ["AND",["condition4"]]]]]