Skip to content
This repository was archived by the owner on Nov 2, 2023. It is now read-only.

Draft 2020-12 release notes #392

Merged
merged 9 commits into from
Jun 29, 2021
2 changes: 0 additions & 2 deletions draft/2019-09/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ title: JSON Schema 2019-09 Release Notes
layout: page
---

_NOTE: This page is still being written, and is currently a fairly minimal listing of changes._

For the vast majority of schema authors, we hope that these changes are minimally disruptive.

The most likely to be frustrating is that `format` is no longer treated as a validation assertion _by default_ (although it is still possible for an application or user to configure a validator to treat it as one). We decided this was acceptable because many schema authors are already extremely frustrated by its inconsistent behavior.
Expand Down
182 changes: 180 additions & 2 deletions draft/2020-12/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,185 @@
title: JSON Schema 2020-12 Release Notes
layout: page
---
## Changes to items and additionalItems
The keywords used for defining arrays and tuples have been redesigned to help
lower the learning curve for JSON Schema. Since the `items` keyword was used for
both types, we would often see people mistakenly defining a tuple when they
meant to define an array and not understand why only the first item in the array
was validating.

_NOTE: This page is still being written._
The `items` and `additionalItems` keywords have been replaced with `prefixItems`
and `items` where `prefixItems` has the same functionality as the
array-of-schemas for of the old `items` and the new `items` keyword has the same
functionality as the old `additionalItems` keyword.

You can find a minimal changelog at the end of the specification documents themselves.
Although the meaning of `items` has changed, the syntax for defining arrays
remains the same. Only the syntax for defining tuples has changed. The idea is
that an array has items (`items`) and optionally has some positionally defined
items that come before the normal items (`prefixItems`).

Here are some examples to illustrate the changes.

### Open tuple
<table>
<tr>
<th>Draft 2019-09</th>
<th>Draft 2020-12</th>
</tr>
<tr>
<td>
<pre>{
"items": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
]
}</pre>
</td>
<td>
<pre>{
"prefixItems": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
]
}</pre>
</td>
</tr>
</table>

### Closed tuple
<table>
<tr>
<th>Draft 2019-09</th>
<th>Draft 2020-12</th>
</tr>
<tr>
<td>
<pre>{
"items": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
],
"additionalItems": false
}</pre>
</td>
<td>
<pre>{
"prefixItems": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
],
"items": false
}</pre>
</td>
</tr>
</table>

### Tuple with constrained additional items
<table>
<tr>
<th>Draft 2019-09</th>
<th>Draft 2020-12</th>
</tr>
<tr>
<td>
<pre>{
"items": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
],
"additionalItems": { "$ref": "#/$defs/baz" }
}</pre>
</td>
<td>
<pre>{
"prefixItems": [
{ "$ref": "#/$defs/foo" },
{ "$ref": "#/$defs/bar" }
],
"items": { "$ref": "#/$defs/baz" }
}</pre>
</td>
</tr>
</table>

## $dynamicRef and $dynamicAnchor
The `$recursiveRef` and `$recursiveAnchor` keywords were replaced by the more
powerful `$dynamicRef` and `$dynamicAnchor` keywords. `$recursiveRef` and
`$recursiveAnchor` were introduced in the previous draft to solve the problem of
extending recursive schemas. As the "recursive" keywords got some use and we
understood them better, we discovered how we could generalize them to solve even
more types of problems. The name change reflects that these keywords are useful
for more than just extending recursive schemas.

A `$dynamicAnchor` can be thought of like a normal `$anchor` except that it can
be referenced across schemas rather than just in the schema it was defined in.
You can think of the old `$recursiveAnchor` as working the same way except that
it only allowed you to create an anchor at the root of the schema and the anchor
name is always empty.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another side effect of using named anchors is that you can have more than one in the same schema (and perhaps overlapping). The tree example could be extended to allow for two different types of branches, each of which is recursive and each references the other.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. That's worth mentioning, but I'd rather keep the example simple. I don't what this to become a tutorial and every time I attempted to give a more complex example, it kept snowballing in that direction. The link to this page is in a section called "Migrating from older drafts", so I think it's reasonable to limit the examples to how to convert a 2019-09 schema to a 2020-12 schema.

`$dynamicRef` works the same as the old `$recursiveRef` except that fragments
are no longer empty (`"$dynamicRef": "#my-anchor"` instead of `"$recursiveRef":
"#"`) and non-fragment-only URIs are allowed. When a `$dynamicRef` contains a
non-fragment-only URI-Reference, the schema the URI-Reference resolves to is
used as the starting point for dynamic resolution.
Comment on lines +133 to +135
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the schema the URI-Reference resolves to is used as the starting point for dynamic resolution" -- I don't think this is right:

If the initially resolved starting point URI includes a fragment that was created by the "$dynamicAnchor" keyword, ... Otherwise, its behavior is identical to "$ref", and no runtime resolution is needed.

(https://json-schema.org/draft/2020-12/json-schema-core.html#rfc.section.8.2.3.2)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the problem. What about these two statements are in conflict?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The release notes seem to be saying that "$dynamicRef": "someuri#/foo/bar/baz" is a valid starting point for dynamic resolution, but in fact URIs of that form can only be treated as if $ref was used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the disconnect might be in the meaning of "dynamic resolution". The way I've used it, it includes the processes of determining whether the fragment is a usable dynamic anchor. If it isn't, the result of dynamic resolution is to do nothing and it's effective behavior is that of $ref (just the initial resolution). Maybe you are considering "dynamic resolution" to mean only be the process after determining that we have a valid dynamic anchor?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I read this as saying that if the target of the initial URI has a $dynamicAnchor present, then the dynamic scope resolution process can continue.

Maybe that entire final sentence can be removed. Implementers need to read the spec fully to understand how to implement this keyword.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that it would work if we remove the sentence, but I think it's better if we can provide some brief explanation of what a non-fragment-only URI-Reference would do after telling people that it's allowed. I'd rather try to improve that sentence.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're just talking about a brief note about what has changed and generally what to expect from that change. That's exactly what this document is for. The comment you reference is about expanding the example to showcase the new functionality. I wouldn't go that far in this case either.


Here's how you would covert a schema using `$recursiveRef` to use `$dynamicRef`.

<table>
<tr>
<th>Draft 2019-09</th>
<th>Draft 2020-12</th>
</tr>
<tr>
<td><pre>// tree schema, extensible
{
"$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": "#" }
}
}
}

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

"$ref": "tree",
"unevaluatedProperties": false
}</pre></td>
<td><pre>// tree schema, extensible
{
"$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" }
}
}
}

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

"$ref": "tree",
"unevaluatedProperties": false
}</pre></td>
</tr>
</table>
4 changes: 1 addition & 3 deletions specification-links.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,12 +307,10 @@ For links to the somewhat more readably formatted versions on this web site, and
- Output examples
- [JSON Schema verbose output example](draft/2020-12/output/verbose-example)

### 2019-09 (formerly known as Draft 8)
### Draft 2019-09 (formerly known as Draft 8)

_**NOTE:** All meta-schema URIs now use `https://`. While currently also available over plain HTTP due to the limitations of GitHub pages and the need to keep prior drafts available over HTTP, only the HTTPS URIs should be used._

### Draft 2019-09

- Specifications
- Core: [draft-handrews-json-schema-02](https://tools.ietf.org/html/draft-handrews-json-schema-02) ([changes](https://tools.ietf.org/html/draft-handrews-json-schema-02#appendix-G))
- Validation: [draft-handrews-json-schema-validation-02](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02) ([changes](https://tools.ietf.org/html/draft-handrews-json-schema-validation-02#appendix-C))
Expand Down
4 changes: 2 additions & 2 deletions specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ Migrating from older drafts
The release notes discuss the changes impacting users and implementers:

- JSON Schema Core and Validation
- 2019-09 to 2020-12 (Work in progress - 2021-02-01)
- [Draft-07 to 2019-09](draft/2019-09/release-notes.html)
- [Draft 2019-09 to Draft 2020-12](draft/2020-12/release-notes.html)
- [Draft-07 to Draft 2019-09](draft/2019-09/release-notes.html)
- [Draft-06 to Draft-07](draft-07/json-schema-release-notes.html)
- [Draft-04 to Draft-06](draft-06/json-schema-release-notes.html)
- JSON Hyper-Schema
Expand Down