You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `$dynamicRef` keyword is a dynamic applicator that allows for runtime resolution of schema references. Unlike the static `$ref`, which resolves the referenced schema at schema load time, `$dynamicRef` defers full resolution until the instance is evaluated. It attempts to resolve the given fragment based on the dynamic scope at that given point in time.
28
-
- This keyword is particularly useful for handling recursive schemas where the schema references itself or where the structure of the schema may change at runtime.
29
-
- If the `$dynamicRef` includes more than just a fragment, the URI except for the fragment is statically resolved first, and then only the fragment is dynamically resolved.
30
-
- Notably, official meta-schemas use this mechanism themselves for defining vocabularies!
27
+
The [`$dynamicRef`]({{< ref "2020-12/core/dynamicref" >}}) keyword is an
28
+
extension of the [`$ref`]({{< ref "2020-12/core/ref" >}}) keyword that enables
29
+
a schema to reference another schema by its dynamic anchor, as declared by the
30
+
[`$dynamicAnchor`]({{< ref "2020-12/core/dynamicanchor" >}}) keyword. When
31
+
resolving a dynamic anchor using this keyword, the base URI of the origin is
32
+
not considered. Instead, the evaluator looks in the [dynamic
33
+
scope](https://json-schema.org/blog/posts/dynamicref-and-generics) and jumps to
34
+
the first encountered occurence of the given dynamic anchor in the [stack of
by Greg Dennis (co-author of the JSON Schema specification) for a hands-on
55
+
discussion of this concept.
56
+
57
+
{{</best-practice>}}
58
+
59
+
{{<learning-more>}}
60
+
61
+
The official JSON Schema meta-schemas define, by convention, a dynamic anchor
62
+
called `meta`. This is a fundamental building block for schema extensibility.
63
+
The meta-schema of every vocabulary (official or third-party) hooks into this
64
+
dynamic anchor to extend the recursive definition of what constitutes a valid
65
+
schema for the given dialect.
66
+
67
+
More specifically, by relying on the `meta` dynamic anchor, a vocabulary
68
+
meta-schema can validate the presence of a new keyword and have those
69
+
constraints be automatically discovered and applied by any applicator of any
70
+
other vocabulary (even future ones).
31
71
32
-
{{<learning-more>}} URIs play a central role in JSON Schema. Going through the URI [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) specification is a must for gaining a deeper understanding of references, identifiers, and
33
-
anchors. More specifically, we recommend carefully studying [URI resolution](https://datatracker.ietf.org/doc/html/rfc3986#section-5), URLs vs URNs, and the difference between a URI and a URI Reference.
34
-
35
-
You may also find these blog posts helpful for gaining a deeper understanding of dynamic references.
36
-
*[Understanding JSON Schema Lexical and Dynamic Scopes](https://json-schema.org/blog/posts/understanding-lexical-dynamic-scopes)
37
-
*[Using Dynamic References to Support Generic Types](https://json-schema.org/blog/posts/dynamicref-and-generics)
38
72
{{</learning-more>}}
39
73
40
74
{{<common-pitfall>}}
41
-
**Bookending:** The bookending requirement means that when you use a `$dynamicRef`, the JSON Schema processor needs to find a matching `$dynamicAnchor` within the target schema resource, even if the target is different from the destination schema. This ensures that the reference resolves correctly by matching the actual anchor defined in the target schema resource, preventing unresolvable references due to scope issues.
42
-
{{</common-pitfall>}}
43
-
44
-
## Examples
45
-
46
-
{{<schema `After leaving a dynamic scope, '$dynamicAnchor' is not used by a '$dynamicRef'`>}}
"$comment": "this is secondScope#thingy, the final destination of the $dynamicRef",
66
-
"$dynamicAnchor": "thingy",
67
-
"type": "null"
68
-
}
69
-
}
70
-
},
71
-
"$defs": {
72
-
"start": {
73
-
"$comment": "this is the landing spot from $ref",
74
-
"$id": "start",
75
-
"$dynamicRef": "innerScope#thingy"
76
-
},
77
-
"thingy": {
78
-
"$comment": "this is the first stop for the $dynamicRef",
79
-
"$id": "innerScope",
80
-
"$dynamicAnchor": "thingy",
81
-
"type": "string"
82
-
}
83
-
}
84
-
}
85
-
{{</schema>}}
86
75
87
-
{{<instance-fail `String matches '/$defs/thingy', but the '$dynamicRef' does not stop here`>}}
88
-
"a string"
89
-
{{</instance-fail>}}
90
-
91
-
{{<instance-fail `firstScope is not in dynamic scope for the '$dynamicRef'`>}}
92
-
42
93
-
{{</instance-fail>}}
94
-
95
-
{{<instance-pass `'/then/$defs/thingy' is the final stop for the '$dynamicRef'`>}}
96
-
null
97
-
{{</instance-pass>}}
76
+
As a fallback, the specification allows the use of this keyword to reference
77
+
static resources and non-dynamic anchors. However, to avoid confusion and keep
78
+
your schemas easy to understand, don't rely on this fallback behaviour. Only
79
+
make use of this keyword to reference dynamic anchors set by the
80
+
[`$dynamicAnchor`]({{< ref "2020-12/core/dynamicanchor" >}}) keyword, without
81
+
making use of any URI component (other than the fragment) as part of the
82
+
reference.
98
83
99
-
- The evaluation begins with the top-level schema, where the dynamic scope is the root schema resource.
100
-
-**Dynamic Scope:**`https://example.com/root`
84
+
{{</common-pitfall>}}
101
85
102
-
- Upon encountering the `if` applicator, a new schema resource (`https://example.com/firstScope`) is declared and added to the stack, expanding the dynamic scope.
command with the `--trace` option. This option prints a trace of every step in
90
+
the evaluation process alongside the corresponding keywords and their
91
+
respective locations, letting you know which destination was preferred when
92
+
encountering a dynamic reference. For example:
104
93
105
-
- Since `https://example.com/firstScope` doesn't reference any other schema resource, the evaluation of the `if` schema completes, and the stack unwinds, returning to the root schema resource.
- The successful validation by the `if` subschema triggers entry into the `then` applicator, introducing another schema resource (`https://example.com/secondScope`), thus extending the dynamic scope.
at keyword location "https://example.com/string-list#/$defs/generic-list-item/type"
106
+
at vocabulary "https://json-schema.org/draft/2020-12/vocab/validation"
113
107
114
-
- Additionally, within the `then` subschema, a dynamic reference is made to another schema resource (`https://example.com/innerScope#thingy`). While the initial part of the URI is resolved statically to `/$defs/thingy`, the inclusion of `#thingy` fragment reults in the final resolution to `/then/$defs/thingy` because the first dynamic anchor encountered in the current dynamic scope is at `/then/$defs/thingy`. So, only a null value is valid in this case.
108
+
...
109
+
```
115
110
116
-
**Note:**_The non-fragment part is always statically resolved, while the fragment may be dynamically resolved._
111
+
## Examples
117
112
118
-
{{<schema `Schema with '$dynamicRef' and '$dynamicAnchor' keywords in the same schema resource`>}}
113
+
{{<schema `A generic schema that describes an array where the items definition (by default anything) can be overriden through a dynamic anchor`>}}
"$comment": "This is a default declaration to satisfy the bookending requirement",
124
+
"$dynamicAnchor": "generic-list-item"
141
125
}
142
126
}
143
127
}
144
128
{{</schema>}}
145
129
146
-
{{<instance-pass `An instance adhering to the above schema is valid`>}}
147
-
{
148
-
"name": "John",
149
-
"age": 35,
150
-
"address": "1234 Elm Street, Springfield, IL 62701, USA"
151
-
}
130
+
{{<instance-pass `An empty array value is valid`>}}
131
+
[]
152
132
{{</instance-pass>}}
153
133
154
-
{{<instance-fail `Required properties must be present`>}}
155
-
{ "name": "Doe", "age": 61 }
156
-
{{</instance-fail>}}
134
+
{{<instance-pass `An array value with arbitrary items is valid`>}}
135
+
[ 1, "foo", false ]
136
+
{{</instance-pass>}}
157
137
158
-
*_A `$dynamicRef` referencing a `$dynamicAnchor` within the same schema resource functions similarly to a standard `$ref` referencing an `$anchor`. Similarly, a `$dynamicRef` referencing an `$anchor` within the same schema resource behaves like a typical `$ref` referencing an `$anchor`. Likewise, a `$ref` targeting a `$dynamicAnchor` within the same schema resource behaves like a regular `$ref` targeting an `$anchor`._
0 commit comments