Skip to content

Commit 258d721

Browse files
authored
Merge pull request #1555 from json-schema-org/gregsdennis/dynamic-ref
clean up `$dynamic*`
2 parents bea3b1f + eec2c4c commit 258d721

File tree

4 files changed

+105
-83
lines changed

4 files changed

+105
-83
lines changed

adr/2024-11-2-assertion-format.md

+66-43
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,101 @@
1-
# [short title of solved problem and solution]
1+
# `format` as an assertion
22

3-
* Status: proposed
3+
- Status: proposed
44
<!-- will update below to only those who participated in the vote -->
5-
* Deciders: @gregsdennis @jdesrosiers @julian @jviotti @mwadams @karenetheridge @relequestual
6-
* Date: 2024-11-02
7-
* Technical Story: https://github.com/json-schema-org/json-schema-spec/issues/1520
8-
* Voting issue: https://github.com/json-schema-org/TSC/issues/19
9-
For - @gregsdennis @jdesrosiers @jviotti @mwadams @karenetheridge
10-
Neutral - @relequestual
11-
Against - @julian
5+
- Deciders: @gregsdennis @jdesrosiers @julian @jviotti @mwadams @karenetheridge
6+
@relequestual
7+
- Date: 2024-11-02
8+
- Technical Story: <https://github.com/json-schema-org/json-schema-spec/issues/1520>
9+
- Voting issue: <https://github.com/json-schema-org/TSC/issues/19>
10+
- For - @gregsdennis @jdesrosiers @jviotti @mwadams @karenetheridge
11+
- Neutral - @relequestual
12+
- Against - @julian
1213

1314
## Context and Problem Statement
1415

1516
There's a long and sticky history around format.
1617

1718
1. Going back all the way to Draft 01, format has never required validation.
18-
2. Whether to support format validation has always been the decision of the implementation.
19-
3. The extent to which formats are validated has also been the decision of the implementation.
20-
21-
The result of all of this is that implementation support for validation has been spotty at best. Despite the JSON Schema specs referencing very concretely defined formats (by referencing other specs), implementations that do support validation don't all support each format equally. This has been the primary driving force behind keeping format as an opt-in validation.
22-
23-
With 2019-09, we decided that it was time to give the option of format validation to the schema author. They could enable validation by using a meta-schema which listed the Format Vocabulary with a true value, which meant, "format validation is required to process this schema."
24-
25-
In 2020-12, we further refined this by offering two separate vocabularies, one that treats the keyword as an annotation and one that treats it as an assertion. The argument was that the behavior of a keyword shouldn't change based on whether the vocabulary was required or not.
26-
27-
However, the fact remains that our users consistently report (via questions in Slack, GitHub, and StackOverflow) that they expect format to validate. (The most recent case I can think of was only last week, in .Net's effort to build a short-term solution for schema generation from types.)
19+
1. Whether to support format validation has always been the decision of the
20+
implementation.
21+
1. The extent to which formats are validated has also been the decision of the
22+
implementation.
23+
24+
The result of all of this is that implementation support for validation has been
25+
spotty at best. Despite the JSON Schema specs referencing very concretely
26+
defined formats (by referencing other specs), implementations that do support
27+
validation don't all support each format equally. This has been the primary
28+
driving force behind keeping format as an opt-in validation.
29+
30+
With 2019-09, we decided that it was time to give the option of format
31+
validation to the schema author. They could enable validation by using a
32+
meta-schema which listed the Format Vocabulary with a true value, which meant,
33+
"format validation is required to process this schema."
34+
35+
In 2020-12, we further refined this by offering two separate vocabularies, one
36+
that treats the keyword as an annotation and one that treats it as an assertion.
37+
The argument was that the behavior of a keyword shouldn't change based on
38+
whether the vocabulary was required or not.
39+
40+
However, the fact remains that our users consistently report (via questions in
41+
Slack, GitHub, and StackOverflow) that they expect format to validate. (The most
42+
recent case I can think of was only last week, in .Net's effort to build a
43+
short-term solution for schema generation from types.)
2844

2945
Due to this consistency in user expectations, we have decided to:
3046

3147
1. make format an assertion keyword, and
32-
2. strictly enforce it by moving the appropriate tests into the required section of the Test Suite and building them more completely.
48+
1. strictly enforce it by moving the appropriate tests into the required section
49+
of the Test Suite and building them more completely.
3350

3451
## Decision Drivers
3552

36-
* User expectation
37-
* Current behavior
38-
* Historical context
39-
* Disparity of current implementation support vs the proposed requirements
53+
- User expectation
54+
- Current behavior
55+
- Historical context
56+
- Disparity of current implementation support vs the proposed requirements
4057

4158
## Considered Options
4259

4360
### `format` remains an annotation keyword by default
4461

45-
This is the current state. The primary benefit is that we don't need to make a breaking change.
46-
47-
The primary downside is that the current system of (1) configuring the tool or (2) incluing the `format-assertion` vocab[^1] is confusing for many and doesn't align with user expectations.
62+
This is the current state. The primary benefit is that we don't need to make a
63+
breaking change.
4864

49-
[^1] The `format-assertion` vocabulary will no longer be an option since we have demoted vocabularies to a proposal for the stable release. This leaves tool configuration as the only option to enable `format` validation.
65+
The primary downside is that the current system of (1) configuring the tool or
66+
(2) incluing the `format-assertion` vocab[^1] is confusing for many and doesn't
67+
align with user expectations.
5068

5169
### `format` becomes an assertion keyword by default
5270

53-
We change the spec to require `format` validation. Furthermore:
71+
We change the spec to require `format` validation. Furthermore:
5472

55-
* Implementations SHOULD support `format` with the defined values
56-
* Implementations MAY support others, but only by explicit config
57-
* Implementations MUST refuse to process a schema that contains an unsupported format
73+
- Implementations SHOULD support `format` with the defined values
74+
- Implementations MAY support others, but only by explicit config
75+
- Implementations MUST refuse to process a schema that contains an unsupported
76+
format
5877

5978
## Decision Outcome
6079

61-
The TSC has decided via vote (see voting issue above) that we should change `format` to act as an assertion by default, in line with option (2).
80+
The TSC has decided via vote (see voting issue above) that we should change
81+
`format` to act as an assertion by default, in line with option (2).
6282

6383
### Positive Consequences <!-- optional -->
6484

65-
* Aligns with user expectations.
66-
* Users are still able to have purely annotative behavior through use of something like `x-format`.
67-
* Increased consistency for `format` validation across implementations.
85+
- Aligns with user expectations.
86+
- Users are still able to have purely annotative behavior through use of
87+
something like `x-format`.
88+
- Increased consistency for `format` validation across implementations.
6889

6990
### Negative Consequences <!-- optional -->
7091

71-
* This is a breaking change, which means that we will likely have to re-educate the users who correctly treat it as an annotation.
72-
* Older schemas which do not specify a version (`$schema`) may change their validation outcome.
73-
* The burden on implementations will be greater since format validation was previously optional.
74-
75-
## Links <!-- optional -->
92+
- This is a breaking change, which means that we will likely have to re-educate
93+
the users who correctly treat it as an annotation.
94+
- Older schemas which do not specify a version (`$schema`) may change their
95+
validation outcome.
96+
- The burden on implementations will be greater since format validation was
97+
previously optional.
7698

77-
* [Link type] [Link to ADR] <!-- example: Refined by [ADR-0005](0005-example.md) -->
78-
*<!-- numbers of links can vary -->
99+
[^1]: The `format-assertion` vocabulary will no longer be an option since we
100+
have demoted vocabularies to a proposal for the stable release. This leaves tool
101+
configuration as the only option to enable `format` validation.

specs/jsonschema-core.md

+37-38
Original file line numberDiff line numberDiff line change
@@ -546,8 +546,8 @@ determined at runtime.
546546

547547
While custom identifier keywords are possible, extension designers should take
548548
care not to disrupt the functioning of core keywords. For example, the
549-
`$dynamicAnchor` keyword in this specification limits its IRI resolution effects
550-
to the matching `$dynamicRef` keyword, leaving the behavior of `$ref`
549+
`$dynamicAnchor` keyword in this specification limits its resolution behavior
550+
to matching `$dynamicRef` keywords, leaving the behavior of `$ref`
551551
undisturbed.
552552

553553
### Applicators {#applicators}
@@ -947,17 +947,18 @@ The `$anchor` and `$dynamicAnchor` keywords are used to specify such fragments.
947947
They are identifier keywords that can only be used to create plain name
948948
fragments, rather than absolute IRIs as seen with `$id`.
949949

950-
The base IRI to which the resulting fragment is appended is the canonical IRI of
951-
the schema resource containing the `$anchor` or `$dynamicAnchor` in question.
952-
As discussed in the previous section, this is either the nearest `$id` in the
953-
same or parent schema object, or the base IRI for the document as determined
954-
according to [RFC 3987](#rfc3987) and [RFC 3986](#rfc3986).
950+
`$anchor` defines a reference target for `$ref`. The fragment defined by this
951+
keyword is appended to the IRI of the schema resource containing it. As
952+
discussed in {{id-keyword}}, this is either the nearest `$id` in the same or an
953+
ancestor schema object, or the base IRI for the document as determined according
954+
to [RFC 3987](#rfc3987) and [RFC 3986](#rfc3986).
955955

956-
Separately from the usual usage of IRIs, `$dynamicAnchor` indicates that the
957-
fragment is an extension point when used with the `$dynamicRef` keyword. This
958-
low-level, advanced feature makes it easier to extend recursive schemas such as
959-
the meta-schemas, without imposing any particular semantics on that extension.
960-
See the section on [`$dynamicRef`](#dynamic-ref) for details.
956+
In contrast, `$dynamicAnchor` operates independently of resource IRIs and is
957+
instead dependent on the dynamic scope of the evaluation. `$dynamicAnchor`
958+
defines a reference target for the `$dynamicRef` keyword. This advanced feature
959+
makes it easier to extend recursive schemas such as the meta-schemas, without
960+
imposing any particular semantics on that extension. See {{dynamic-ref}} for
961+
details.
961962

962963
In most cases, the normal fragment behavior both suffices and is more intuitive.
963964
Therefore it is RECOMMENDED that `$anchor` be used to create plain name
@@ -980,18 +981,9 @@ result is undefined, and even if documented will not be interoperable.
980981

981982
#### Schema References {#references}
982983

983-
Several keywords can be used to reference a schema which is to be applied to the
984-
current instance location. `$ref` and `$dynamicRef` are applicator keywords,
985-
applying the referenced schema to the instance.
986-
987-
As the values of `$ref` and `$dynamicRef` are IRI References, this allows the
988-
possibility to externalise or divide a schema across multiple files, and
989-
provides the ability to validate recursive structures through self-reference.
990-
991-
The resolved IRI produced by these keywords is not necessarily a network
992-
locator, only an identifier. A schema need not be downloadable from the address
993-
if it is a network-addressable URL. Implementations which can access the network
994-
SHOULD default to operating offline.
984+
`$ref` and `$dynamicRef` can be used to reference a schema which is to be
985+
applied to the current instance location. As such, they are considered
986+
applicators, applying the referenced schema to the instance.
995987

996988
##### Direct References with `$ref` {#ref}
997989

@@ -1006,31 +998,38 @@ Resolved against the current IRI base, it produces the IRI of the schema to
1006998
apply. This resolution is safe to perform on schema load, as the process of
1007999
evaluating an instance cannot change how the reference resolves.
10081000

1001+
The resolved IRI produced by `$ref` is not necessarily a network
1002+
locator, only an identifier. A schema need not be downloadable from the address
1003+
if it is a network-addressable URL. Implementations which can access the network
1004+
SHOULD default to operating offline.
1005+
10091006
##### Dynamic References with `$dynamicRef` {#dynamic-ref}
10101007

10111008
The `$dynamicRef` keyword is an applicator that allows for deferring the full
10121009
resolution until runtime, at which point it is resolved each time it is
10131010
encountered while evaluating an instance.
10141011

10151012
Together with `$dynamicAnchor`, `$dynamicRef` implements a cooperative extension
1016-
mechanism that is primarily useful with recursive schemas (schemas that
1017-
reference themselves). The extension point is defined with `$dynamicAnchor` and
1018-
only exhibits runtime dynamic behavior when referenced with `$dynamicRef`.
1013+
mechanism that is primarily useful to to create open schemas, where
1014+
`$dynamicRef` defines the extension point and `$dynamicAnchor` defines the
1015+
target.
1016+
1017+
The value of the `$dynamicRef` property MUST be formatted as a valid
1018+
[IRI plain name fragment](#fragments).[^3]
10191019

1020-
The value of the `$dynamicRef` property MUST be a string which is a
1021-
IRI reference that contains a valid [plain name fragment](#anchors). Resolved
1022-
against the current IRI base, it indicates the schema resource used as the
1023-
starting point for runtime resolution. This initial resolution is safe to
1024-
perform on schema load.
1020+
[^3]: `$dynamicAnchor` defines the anchor with plain text, e.g. `foo`. Although
1021+
the value of `$dynamicRef` is not an IRI fragment, for historical reasons, the
1022+
value still uses an IRI fragment syntax, e.g. `#foo`.
10251023

1026-
The schema to apply is the outermost schema resource in the [dynamic
1027-
scope](#scopes) that defines a `$dynamicAnchor` that matches the plain name
1028-
fragment in the initially resolved IRI.
1024+
Resolution of `$dynamicRef` begins by identifying the outermost schema
1025+
resource in the [dynamic scope](#scopes) which defines a matching
1026+
`$dynamicAnchor`. The schema to apply is the subschema of this resource which
1027+
contains the matching `$dynamicAnchor`.
10291028

1030-
For a full example using these keyword, see {{recursive-example}}.[^6]
1029+
For a full example using these keywords, see {{recursive-example}}.[^6]
10311030

1032-
[^6]: The difference between the hyper-schema meta-schema in pre-2019 drafts and
1033-
an this draft dramatically demonstrates the utility of these keywords.
1031+
[^6]: The differences in the hyper-schema meta-schemas from draft-07 and draft
1032+
2019-09 dramatically demonstrates the utility of these keywords.
10341033

10351034
#### Schema Re-Use With `$defs` {#defs}
10361035

specs/jsonschema-use-cases.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</address>
2424
</author>
2525

26-
<date year="2024"/>
26+
<date year="2025"/>
2727
<workgroup>JSON Schema</workgroup>
2828
<keyword>JSON</keyword>
2929
<keyword>Schema</keyword>

specs/relative-json-pointer.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
</address>
4141
</author>
4242

43-
<date year="2024"/>
43+
<date year="2025"/>
4444
<workgroup>Internet Engineering Task Force</workgroup>
4545
<keyword>JSON</keyword>
4646
<keyword>JavaScript</keyword>

0 commit comments

Comments
 (0)