json-schema for enumerated properties/keys - jsonschema

I have a JSON document like this
{
"visits": {
"1": 1000,
"2": 300,
"3": 43,
}
}
But all of the keys ("1", "2", "3") are actually an enumeration and it is stored as integer for storage saving purpose. I want to document the description of the enumeration. For example.
1 => When the user is guest
2 => When the user is logged in
3 => When the user is admin
How do I put this in the json schema?

You could use patternProperties to describe the numeric properties, and then additionalProperties to disallow any properties that don't match the pattern:
{
"type": "object",
"patternProperties": {
"^(0|[1-9][0-9]*)$": {"type": "string"}
},
"additionalProperties": false
}
So here, any property that matches ^(0|[1-9][0-9]*)$ (non-negative integer) must be a string, and other properties are not allowed.
(If you're looking to enforce some kind of ordering (e.g. "5" must only exist if "4" is also defined) then you can't express that with JSON Schema.)

Related

Does Json Schema allow a property's definition to reference another property?

I'd like to create a JSON schema that restricts one property's values based on another property's values.
An example valid object might look like this:
{
"lookup": {
"foo": "string",
"bar": "number",
},
// properties in `values` must exist in `lookup`
"values": {
// `foo` must be a string
"foo": "string is OK",
// `bar` must be a number
"bar": 100
}
}
The idea is for the schema to enforce a relationship between the two properties.
{
"type": "object",
"properties": {
"lookup" : {
"type": "object",
"additionalProperties" : {
"type": "string",
"enum": ["string", "number"]
}
},
"values": {
"type": "object",
// - this value's properties must exist in `lookup`
// - if the property in `lookup` is set to `string`, the type here must be `string`; if the property in `lookup` is set to `number`, the type here must be `number`
}
}
}
This is possible in some cases. While you can't restrict a piece of data to certain values taken from other parts of the data (for example: using property X to provide a list of values that property Y can have), you can specify conditionals between parts of your schema.
requirement 1: this value's properties must exist in lookup -> not possible
requirement 2: if the property in lookup is set to string, the type here must be string; if the property in lookup is set to number, the type here must be number -> possible
See https://json-schema.org/understanding-json-schema/reference/conditionals.html for the various options available to you.
This is not possible with the standard specification of JSON Schema.

Validate phone only when provided using Json Schema

Using following JSON schema to validate phone number if provided.
Accepted validation
Min length 10
Max length 20
and Pattern
If phone is null or empty, no validation is required
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"Item": {
"type": "object",
"properties": {
"Phone": {
"anyOf": [
{
"type": "integer",
"minLength": 10,
"maxLength": 20,
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
},
{
"type": [ "integer", "null" ]
}
]
}
}
}
}
}
Can you please suggest what is missing in the above schema?
Thank you!
Remove integer from the null case. It's slowing so integers through, which overrides the phone number case.
Secondarily, if possible, you may want to use a later draft for your schema. Draft 4 is quite old. Check with your validator to see if it supports a newer draft.
There are errors in your schema, but you're missing the understanding about how JSON Schema works in terms of applicability.
JSON Schema has many keywords that are only applicable to a specific type. When the type is not that of a keywords applicability, it has no effect.
The subschema for "phone" can be simplified as the following:
{
"type": ["string", "null"],
"minLength": 10,
"maxLength": 20,
"pattern": "^(\\([0-9]{3}\\))?[0-9]{3}-[0-9]{4}$"
}
The keywords minLenght, maxLength, and pattern are only applicable to strings. If the value is not a string (and is null), those keywords are not applicable, and so are ignored.
(I've not checked your regex here, just copied what you had already.)

Validating that a property value exists withing the keys of an object

Wise crowd,
I already have a working JSON Schema (v0.7) to validate my data. This is an example of valid JSON:
{
"people": [
{ "id": 1, "name": "bob" },
...
]
}
Now I need to a bunch of strings in it:
{
"people": [
{ "id": 1, "name": "bob", "appears_in": "long_string_id_1" },
{ "id": 2, "name": "ann", "appears_in": "long_string_id_1" }
...
],
"long_strings": {
"long_string_id_1": "blah blah blah.....",
...
}
}
What I need is:
a value for key appears_in MUST be a key of the long_strings object
(optional) a key of the long_strings object MUST be used as value in on of the appears_in key
Property dependencies are nice, but don't seem to address my needs.
Any idea?
And this question is not a duplicate, because I do not know the values in advance.
Sorry. You cannot do this in JSON schema. You cannot reference data in your schema.

Have one property define the types in another array property, using JSON Schema?

Given this example JSON:
{
"type": "number",
"values": [ 34, 42, 99 ]
}
Is it possible to define JSON Schema that makes sure that the contents of
the values array are of the type specified in another property (in this example type)?
Above type is saying that the array values can only contain integers (using the specifier "number").
Or specify that values contains strings:
{
"type": "string",
"values": [ "hello", "world" ]
}
Yes you can use the "items" keyword. If it has a single value then that value is the schema for every element of the array.
{
"type": "array",
"items": { "type: "string" }
}
Assuming you're using a draft4 schema like most people do, section 8.2.3.1 of the specification states:
8.2.3.1. If "items" is a schema
If items is a schema, then the child instance must be valid against
this schema, regardless of its index, and regardless of the value of
"additionalItems".
Yes, but you will have to write an if/then block for each type you want to support.
The Understanding JSON Schema has a section on if/then/else: http://json-schema.org/understanding-json-schema/reference/conditionals.html
Here is an extract that explains how if/then/else works.
For example, let’s say you wanted to write a schema to handle
addresses in the United States and Canada. These countries have
different postal code formats, and we want to select which format to
validate against based on the country. If the address is in the United
States, the postal_code field is a “zipcode”: five numeric digits
followed by an optional four digit suffix. If the address is in
Canada, the postal_code field is a six digit alphanumeric string where
letters and numbers alternate.
{
"type": "object",
"properties": {
"street_address": {
"type": "string"
},
"country": {
"enum": ["United States of America", "Canada"]
}
},
"if": {
"properties": { "country": { "const": "United States of America" } }
},
"then": {
"properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } }
},
"else": {
"properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } }
}
}
For each type you want to support, you would need to write if/then object, and wrap all of them in an allOf.

reusing an object for multiple JSON schemas

I have two separate JSON schemas (used to validate HTTP request endpoints for a REST API) where they both accept the same exact object, but have different required fields (this is a create vs update request). Is there a way I can reuse a single definition of this object and only change the required fields? I know how to use $ref for reusing an object as a property of another object, but I cannot figure out how to reuse an entire object as the top-level object in a schema. My failed attempt so far:
event.json
{
"id": "event",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"start_date": {
"type": "integer"
},
"end_date": {
"type": "integer"
},
"description": {
"type": "string"
}
},
"additionalProperties": false
}
event-create.json
{
"id": "event-create",
"type": "object",
"$ref": "event",
"additionalProperties": false,
"required": [ "name", "description" ]
}
Obviously that doesn't work. It seems like it tries to insert the entirety of 'event' into the definition of 'event-create', including the ID and such. I tried referincing event#/properties to no avail. I can't seem to do a $ref as the sole value inside a properties property either. Any ideas?
Any members other than "$ref" in a JSON Reference object SHALL be ignored.
- https://datatracker.ietf.org/doc/html/draft-pbryan-zyp-json-ref-03#section-3
This is why your example doesn't work. Anything other than the $ref field is supposed to be ignored.
Support for $ref is limited to fields whose type is a JSON Schema. That is why trying to use it for properties doesn't work. properties is a plain object whose values are JSON Schemas.
The best way to do this is with allOf. In this case allOf can sort-of be thought of as a list of mixin schemas.
{
"id": "event-create",
"type": "object",
"allOf": [{ "$ref": "event" }],
"required": ["name", "description"]
}
I found some syntax that seems to work, but I'm not terribly happy with it:
{
"id": "event-create",
"allOf": [
{ "$ref": "event" },
{ "required": [ "name", "description" ] }
]
}
Seems like an abuse of the allOf operator, particularly for another case where there are no required fields (thus only one element insid the allof). But it works, so I'm going with it unless someone has a better idea.