References

Resolve references using $ref keyword

Remember when we mentioned about the $id keyword in the JSON Schema Structure? Now is time to use that $id for something. As we said, a JSON Schema document can be identified by an unique id.

Consider that we have two JSON Schema documents: one validates a custom email address and the other one validates an user which must have that custom email address. In order to reuse the custom email validator we make a reference to it by using the $ref keyword. Let’s see how it will look.

{
  "$id": "http://example.com/custom-email-validator.json#",
  
  "type": "string",
  "format": "email",
  "pattern": "@example\\.test$"
}
{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2
    },
    "email": {
      "$ref": "http://example.com/custom-email-validator.json#"
    }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}
Input Status
{"name": "Opis", "email": "opis@example.test"} valid
{"name": "Opis", "email": "opis@example.com"} invalid - pattern not matched

And what happens here is something which produces a result similar to the following schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 2
    },
    "email": {
        "type": "string",
        "format": "email",
        "pattern": "@example\\.test$"
    }
  },
  "required": ["name", "email"],
  "additionalProperties": false
}

This is pretty cool because now you can write and link different schemas. You can use $ref wherever you need, as many times as you need.

This is the first step in schema reusing.

$ref

An instance is valid against this keyword if is valid against the schema that points to the location indicated in the value of this keyword. The value of this keyword must be a string representing an URI, URI reference, URI template or a JSON pointer.

In draft-06 and draft-07 sibling keywords are ignored. Starting with draft-2019-09 sibling keywords are evaluated.

This keyword can be applied to any instance type.

To make $ref a powerful tool, we added a few sibling keywords that will make your life easier:

$recursiveRef

This keyword is an attempt to create extensible schemas. We do not recommend using it, unless you fully understand its behavior!

The value of this keyword must be a string const with value #. It behaves like $ref but the base URI is resolved dynamically using $recursiveAnchor keyword.

{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "https://example.com/tree",
  "$recursiveAnchor": true,

  "type": "object",
  "properties": {
    "data": true,
    "children": {
      "type": "array",
      "items": {
        "$recursiveRef": "#"
      }
    }
  }
}
{
  "$schema": "https://json-schema.org/draft/2019-09/schema",
  "$id": "https://example.com/strict-tree",
  "$recursiveAnchor": true,

  "$ref": "tree",
  "unevaluatedProperties": false
}
Input Status
{"children": [ { "data": 1 } ]} valid
{"children": [ { "daat": 1 } ]} invalid - instance with misspelled field

$recursiveAnchor

This keyword is an attempt to create extensible schemas. We do not recommend using it, unless you fully understand its behavior!

This keyword is used to dynamically identify a base URI at runtime for $recursiveRef by marking where such a calculation can start, and where it stops. If set to true, then when the containing schema object is used as a target of $recursiveRef, a new base URI is determined by examining the dynamic scope for the outermost schema that also contains $recursiveAnchor with a value of true. The base URI of that schema is then used as the dynamic base URI. If no such schema exists, then the base URI is unchanged. If this keyword is set to false, the base URI is unchanged. The value of this keyword must be a boolean.

$dynamicRef

This keyword is an attempt to create extensible schemas. We do not recommend using it, unless you fully understand its behavior!

This keyword is the successor of $recursiveRef. The value of this keyword must be a string representing a fragment. It behaves like $ref but the base URI is resolved dynamically using $dynamicAnchor keyword.

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/tree",
  "$dynamicAnchor": "node",

  "type": "object",
  "properties": {
    "data": true,
    "children": {
      "type": "array",
      "items": {
        "$dynamicRef": "#node"
      }
    }
  }
}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/strict-tree",
  "$dynamicAnchor": "node",

  "$ref": "tree",
  "unevaluatedProperties": false
}
Input Status
{"children": [ { "data": 1 } ]} valid
{"children": [ { "daat": 1 } ]} invalid - instance with misspelled field

$dynamicAnchor

This keyword is an attempt to create extensible schemas. We do not recommend using it, unless you fully understand its behavior!

This keyword is the successor of $recursiveAnchor. The value of this keyword must be a string. If the value of this keyword equals the fragment value from the $dynamicRef keyword then it behaves like $recursiveAnchor being set to true.