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

Commit d47fb89

Browse files
committed
Updates to structuring.rst for Draft 6
1 parent 10a2cf3 commit d47fb89

File tree

1 file changed

+157
-22
lines changed

1 file changed

+157
-22
lines changed

source/structuring.rst

Lines changed: 157 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,13 @@ For this example, let's say we want to define a customer record, where
2222
each customer may have both a shipping and a billing address.
2323
Addresses are always the same---they have a street address, city and
2424
state---so we don't want to duplicate that part of the schema
25-
everywhere we want to store an address. Not only does it make the
25+
everywhere we want to store an address. Not only would that make the
2626
schema more verbose, but it makes updating it in the future more
27-
difficult. If our imaginary company were to start international
27+
difficult. If our imaginary company were to start doing international
2828
business in the future and we wanted to add a country field to all the
2929
addresses, it would be better to do this in a single place rather than
3030
everywhere that addresses are used.
3131

32-
.. note::
33-
This is part of the draft 4 spec only, and does not exist in draft 3.
34-
3532
So let's start with the schema that defines an address::
3633

3734
{
@@ -72,17 +69,22 @@ refer to the above, we would include::
7269

7370
{ "$ref": "#/definitions/address" }
7471

75-
The value of ``$ref`` is a string in a format called `JSON Pointer
72+
This can be used anywhere a schema is expected. You will always use ``$ref`` as
73+
the only key in an object: any other keys you put there will be ignored by the
74+
validator.
75+
76+
The value of ``$ref`` is a URI, and the part after ``#`` sign (the
77+
"fragment" or "named anchor") is in a format called `JSON Pointer
7678
<https://tools.ietf.org/html/rfc6901>`__.
7779

7880
.. note::
7981
JSON Pointer aims to serve the same purpose as `XPath
8082
<http://www.w3.org/TR/xpath/>`_ from the XML world, but it is much
8183
simpler.
8284

83-
The pound symbol (``#``) refers to the current document, and then the
84-
slash (``/``) separated keys thereafter just traverse the keys in the
85-
objects in the document. Therefore, in our example
85+
If you're using a definition from the same document, the ``$ref`` value begins
86+
with the pound symbol (``#``). Following that, the slash-separated items traverse
87+
the keys in the objects in the document. Therefore, in our example
8688
``"#/definitions/address"`` means:
8789

8890
1) go to the root of the document
@@ -139,22 +141,108 @@ schema for a customer:
139141
}
140142
}
141143

144+
.. note::
145+
146+
Even though the value of a ``$ref`` is a URI, it is not a network locator,
147+
only an identifier. The schema may not actually exist at the address
148+
specified. It is basically up to the validator implementation how external
149+
schema URIs will be handled, but one should not assume the validator will
150+
fetch network resources indicated in ``$ref`` values.
151+
152+
Recursion
153+
`````````
154+
155+
``$ref`` elements may be used to create recursive schemas that refer to themselves.
156+
For example, you might have a ``person`` schema that has an array of ``children``, each of which are also ``person`` instances.
157+
158+
.. schema_example::
159+
160+
{
161+
"$schema": "http://json-schema.org/draft-06/schema#",
162+
163+
"definitions": {
164+
"person": {
165+
"type": "object",
166+
"properties": {
167+
"name": { "type": "string" },
168+
"children": {
169+
"type": "array",
170+
* "items": { "$ref": "#/definitions/person" },
171+
"default": []
172+
}
173+
}
174+
}
175+
},
176+
177+
"type": "object",
178+
179+
"properties": {
180+
"person": { "$ref": "#/definitions/person" }
181+
}
182+
}
183+
--
184+
// A snippet of the British royal family tree
185+
{
186+
"person": {
187+
"name": "Elizabeth",
188+
"children": [
189+
{
190+
"name": "Charles",
191+
"children": [
192+
{
193+
"name": "William",
194+
"children": [
195+
{ "name": "George" },
196+
{ "name": "Charlotte" }
197+
]
198+
},
199+
{
200+
"name": "Harry"
201+
}
202+
]
203+
}
204+
]
205+
}
206+
}
207+
208+
However, a loop of ``$ref`` schemas referring to one another could cause
209+
infinite recursion in the validator, and is explicitly disallowed.
210+
211+
.. schema_example::
212+
213+
{
214+
"definitions": {
215+
"alice": {
216+
"anyOf": [
217+
{ "$ref": "#/definitions/bob" }
218+
]
219+
},
220+
"bob": {
221+
"anyOf": [
222+
{ "$ref": "#/definitions/alice" }
223+
]
224+
}
225+
}
226+
}
227+
228+
.. index::
229+
single: $id
230+
142231
.. _id:
143232

144233
The $id property
145234
----------------
146235

147-
|draft6|
148-
149-
The ``$id`` property serves two purposes:
236+
The ``$id`` property is a URI that serves two purposes:
150237

151238
- It declares a unique identifier for the schema.
152239

153-
- It declares a base URL against which ``$ref`` URLs are resolved.
240+
- It declares a base URI against which ``$ref`` URIs are resolved.
154241

155-
It is best practice that ``$id`` is a URL, preferably in a domain that
156-
you control. For example, if you own the ``foo.bar`` domain, and you
157-
had a schema for addresses, you may set its ``$id`` as follows:
242+
It is best practice that every top-level schema should set ``$id`` to an
243+
absolute URI, with a domain that you control. For example, if you own the
244+
``foo.bar`` domain, and you had a schema for addresses, you may set its ``$id``
245+
as follows:
158246

159247
.. schema_example::
160248

@@ -171,25 +259,72 @@ For example, if you had:
171259

172260
{ "$ref": "person.json" }
173261

174-
in the same file, a JSON schema validation library would fetch ``person.json``
175-
from ``http://foo.bar/schemas/person.json``, even if ``address.json`` was loaded
176-
from somewhere else, such as the local filesystem.
262+
in the same file, a JSON schema validation library that supported network
263+
fetching would fetch ``person.json`` from
264+
``http://foo.bar/schemas/person.json``, even if ``address.json`` was loaded from
265+
somewhere else, such as the local filesystem.
266+
267+
|draft6|
177268

178269
.. draft_specific::
179270

180271
--Draft 4
181272
In Draft 4, ``$id`` is just ``id`` (without the dollar sign).
182273

274+
The ``$id`` property should never be the empty string or an empty fragment
275+
(``#``), since that doesn't really make sense.
276+
277+
Using $id with $ref
278+
```````````````````
279+
280+
``$id`` also provides a way to refer to subschema without using JSON Pointer.
281+
This means you can refer to them by a unique name, rather than by where they
282+
appear in the JSON tree.
283+
284+
Reusing the address example above, we can add an ``$id`` property to the
285+
address schema, and refer to it by that instead.
286+
287+
.. schema_example::
288+
289+
{
290+
"$schema": "http://json-schema.org/draft-06/schema#",
291+
292+
"definitions": {
293+
"address": {
294+
*"$id": "#address",
295+
"type": "object",
296+
"properties": {
297+
"street_address": { "type": "string" },
298+
"city": { "type": "string" },
299+
"state": { "type": "string" }
300+
},
301+
"required": ["street_address", "city", "state"]
302+
}
303+
},
304+
305+
"type": "object",
306+
307+
"properties": {
308+
*"billing_address": { "$ref": "#address" },
309+
*"shipping_address": { "$ref": "#address" }
310+
}
311+
}
312+
313+
.. note::
314+
315+
This functionality isn't currently supported by the Python ``jsonschema``
316+
library.
317+
183318
Extending
184319
---------
185320

186-
The power of ``$ref`` really shines when it is combined with the
321+
The power of ``$ref`` really shines when it is used with the
187322
combining keywords ``allOf``, ``anyOf`` and ``oneOf`` (see
188323
:ref:`combining`).
189324

190-
Let's say that for shipping address, we want to know whether the
325+
Let's say that for a shipping address, we want to know whether the
191326
address is a residential or business address, because the shipping
192-
method used may depend on that. For the billing address, we don't
327+
method used may depend on that. For a billing address, we don't
193328
want to store that information, because it's not applicable.
194329

195330
To handle this, we'll update our definition of shipping address::

0 commit comments

Comments
 (0)