Validate phone only when provided using Json Schema - jsonschema

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

Related

jsonschema dependentSchema not validating

I am trying to learn json schema, but something isn't working out for me.
I'm trying to run the example from http://json-schema.org/understanding-json-schema/reference/conditionals.html#id4 for dependentSchemas, but it just doesn't validate.
I'm using this schema:
check_schema = {"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": { "type": "string" },
"credit_card": { "type": "number" }
},
"required": ["name"],
"dependentSchemas": {
"credit_card": {
"properties": {
"billing_address": { "type": "string" }
},
"required": ["billing_address"]
}
}
}
and this json, that should raise an error since it is missing the key billing_address:
check_dict={
"name": "John Doe",
"credit_card": 5555555555555555
}
but when I use jsonschema.validate(dic_check, schema_check) (with python, jsonschema package version 4.2.1), the validation passes with no issues.
What am I doing wrong here?
If you are using an implementation that doesn't support at least draft2019-09 of the specification, dependentSchemas won't be recognized as a keyword. In earlier versions (draft7 and before), that keyword was known as dependencies, with the same syntax (actually, dependencies was split into two, dependentSchemas and dependentRequired).
The details are described on the page you linked, https://json-schema.org/understanding-json-schema/reference/conditionals.html#dependentschemas.
If you still believe that what you have should work, I suggest you open a bug report on the implementation's issue queue.

Is it possible to be agnostic on the properties' names?

Let's say I want to have a schema for characters from a superhero comics. I want the schema to validate json objects like this one:
{
"Name": "Roberta",
"Age": 15,
"Abilities": {
"Super_Strength": {
"Cost": 10,
"Effect": "+5 to Strength"
}
}
}
My idea is to do it like that:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "characters_schema.json",
"title": "Characters",
"description": "One of the characters for my game",
"type": "object",
"properties": {
"Name": {
"type": "string"
},
"Age": {
"type": "integer"
},
"Abilities": {
"description": "what the character can do",
"type": "object"
}
},
"required": ["Name", "Age"]
}
And use a second schema for abilities:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "abilities_schema.json",
"title": "Abilities",
"type": "object",
"properties": {
"Cost": {
"description": "how much mana the ability costs",
"type": "integer"
},
"Effect": {
"type": "string"
}
}
}
But I can't figure how to merge Abilities in Characters. I could easily tweak the schema so that it validates characters formatted like:
{
"Name": "Roberta",
"Age": 15,
"Abilities": [
{
"Name": "Super_Strength"
"Cost": 10,
"Effect": "+5 to Strength"
}
]
}
But as I need the name of the ability to be used as a key I don't know what to do.
You need to use the additionalProperties keyword.
The behavior of this keyword depends on the presence and annotation
results of "properties" and "patternProperties" within the same schema
object. Validation with "additionalProperties" applies only to the
child values of instance names that do not appear in the annotation
results of either "properties" or "patternProperties".
https://json-schema.org/draft/2020-12/json-schema-core.html#rfc.section.10.3.2.3
In laymans terms, if you don't define properties or patternProperties the schema value of additionalProperties is applied to all values in the object at that instance location.
Often additionalProperties is only given a true or false value, but rememeber, booleans are valid schema values.
If you have constraints on the keys for the object, you may wish to use patternPoperties followed by additionalProperties: false.

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.

Dredd (gavel) : Begin a Json Schema with an array (bug ?)

I am using Markdown for Generate documentation (aglio), generate mocks (api-mock) and check the integrity constraints (dredd).
With Dredd, no problem for check an object, no problem for PUT or POST, but I have a problem with lists.
My lists are arrays, but when I write this schema :
{
"title": "Videos List",
"type": "array",
"items": {
"type":"object",
"required":false,
"properties": {
"id": {
"type": "string",
"required": true
}
},
"required": true
}
}
I get same error all the time: body: JSON schema is not valid! invalid type: object (expected [object Object]/array) at path "/items"
I've tried, again and again, 3 hours, but I failed.
Please help!
PS : sorry for my English, I'm french.
Yes, your data is correct again that schema.
It might be a specific problem of the validator your are using (you did not mention which). You can try to enclose your data with {}. I guess it is expecting allways a JSON like this:
{
[
{
"id": "ninon-retrouve-rudy",
"title": "Ninon retrouve Rudy edited"
},
{
"id": "ninon-retrouve-rudy-1",
"title": "Ninon retrouve Rudy"
}
]
}
Be aware also that your are using Draft03 of Json-schema. I suggest you to use Draft04 (your validator might be obsolete).