VOOZH about

URL: https://opis.io/json-schema/2.x/definitions.html

⇱ JSON Schema definitions | Opis JSON Schema


Definitions

definitions keyword

There are cases when you want to reuse validations that are specific only to that schema document, or you simply want to group multiple sub-schemas together. For example, we have a custom email validator, and a custom username validator, and we want to apply those validators multiple times. This can be easily achieved using $ref keyword and the $defs keyword.

In drafts 06 and 07 $defs keyword was named definitions, this has changed starting with draft 2019-09. Don’t worry, definitions can still be used (you can use any name, it doesn’t really matter).

{
 "type": "object",
 "properties": {
 "username": {"$ref": "#/$defs/custom-username"},
 "aliases": {
 "type": "array",
 "items": {"$ref": "#/$defs/custom-username"}
 },
 "primary_email": {"$ref": "#/$defs/custom-email"},
 "other_emails": {
 "type": "array",
 "items": {"$ref": "#/$defs/custom-email"}
 }
 },
 
 "$defs": {
 "custom-username": {
 "type": "string",
 "minLength":3
 },
 "custom-email": {
 "type": "string",
 "format": "email",
 "pattern": "\\.com$"
 }
 }
}
Input Status
{"username": "opis", "primary_email": "opis@example.com"} valid
{"aliases": ["opis json schema", "opis the lib"]} valid
{"other_emails": ["opis@example.com", "opis.lib@example.com"]} valid
{"username": "ab", "primary_email": "opis@example.test"} invalid
{"aliases": ["opis", "ab"]} invalid
{"other_email": ["opis@example.test"]} invalid

Ok, let’s see what happens there. The confusing thing is the value of the $ref keyword, which is something like this #/$defs/something. That’s an URI fragment (starts with #), and the rest of the string after the # represents a JSON pointer. JSON pointers are covered in the next chapter, but we still explain the behavior in a few words, using our example.

Consider this JSON pointer /$defs/custom-email. Because the pointer starts with / (slash) we know that we begin at the root of the schema document. Every substring delimited by a / slash, will be used as property name (key) to descend. In our case we have two substrings: $defs and custom-email.

Descending into $defs gives us

{
 "custom-username": {
 "type": "string",
 "minLength":3
 },
 "custom-email": {
 "type": "string",
 "format": "email",
 "pattern": "\\.com$"
 }
}

And from here, descending into custom-email gives us

{
 "type": "string",
 "format": "email",
 "pattern": "\\.com$"
}

Now, this is the value given by our JSON pointer.

Examples

Definition referencing other definition

{
 "type": "object",
 "properties": {
 "name": {
 "type": "string"
 },
 "personal_data": {
 "$ref": "#/$defs/personal"
 }
 },
 
 "$defs": {
 "email": {
 "type": "string",
 "format": "email" 
 },
 "personal": {
 "type": "object",
 "properties": {
 "mail": {
 "$ref": "#/$defs/email"
 }
 }
 }
 }
}
Input Status
{"name": "John", "personal_data": {"mail": "john@example.com"}} valid
{"name": "John", "personal_data": {"mail": "invalid-email"}} invalid
{"name": "John", "personal_data": "john@example.com"} invalid

Recursive validation

{
 "type": "object",
 "properties": {
 "name": {
 "type": "string"
 },
 "best_friend": {
 "$ref": "#/$defs/friend"
 }
 },
 
 "$defs": {
 "friend": {
 "type": "object",
 "properties": {
 "name": {
 "type": "string"
 },
 "friends": {
 "type": "array",
 "items": {
 "$ref": "#/$defs/friend"
 }
 }
 }
 }
 }
}
{
 "name": "John",
 "best_friend": {
 "name": "The dog"
 }
}
{
 "name": "John",
 "best_friend": {
 "name": "The dog",
 "friends": [
 {
 "name": "The neighbor's dog",
 "friends": [
 {
 "name": "Underdog"
 },
 {
 "name": "Scooby-Doo"
 }
 ]
 }
 ]
 }
}
{
 "name": "John",
 "best_friend": "The dog"
}
{
 "name": "John",
 "best_friend": {
 "name": "The dog",
 "friends": ["Underdog", "Scooby-Doo"]
 }
}
Copyright © Zindex Software. All rights reserved
👁 Image