Skip to content

Commit 49d9748

Browse files
committed
Improve $defs
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 6cb5d49 commit 49d9748

File tree

1 file changed

+36
-77
lines changed

1 file changed

+36
-77
lines changed

content/2020-12/core/defs.markdown

Lines changed: 36 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -20,102 +20,61 @@ related:
2020
keyword: $dynamicRef
2121
---
2222

23-
The `$defs` keyword provides a standardized way to define reusable subschemas within a single schema document, promoting modularity, reducing code duplication, and improving schema organization. Each subschema within `$defs` has a unique name, acting as a location for referencing, without directly affecting validation.
23+
The `$defs` keyword is a container for storing re-usable schemas within a
24+
schema resource, which can be referenced using the [`$ref`]({{< ref
25+
"2020-12/core/ref" >}}) or [`$dynamicRef`]({{< ref "2020-12/core/dynamicref"
26+
>}}) keywords. From a software engineering point of view, this keyword is
27+
analogous to defining _internal_ helper functions as part of a larger program.
2428

25-
## Examples
29+
{{<best-practice>}}
2630

27-
{{<schema `Schema that describes the age of a person`>}}
28-
{
29-
"$schema": "https://json-schema.org/draft/2020-12/schema",
30-
"type": "object",
31-
"properties": {
32-
"age": {
33-
"$ref": "#/$defs/positiveInteger"
34-
}
35-
},
36-
"$defs": {
37-
"positiveInteger": {
38-
"type": "integer",
39-
"minimum": 0
40-
}
41-
}
42-
}
43-
{{</schema>}}
31+
Use this keyword to reduce duplication of internal declarations within a
32+
schema. However, **prefer extracting standalone entities that represent more
33+
than just internal helpers into separate schema files**, and externally
34+
referencing them instead. Otherwise, you will end up with big monolithic
35+
schemas that are challenging to understand and maintain.
4436

45-
{{<instance-pass `The instance has a valid "age" property that meets the requirement specified in the "/$defs/positiveInteger" subschema`>}}
46-
{ "age": 25 }
47-
{{</instance-pass>}}
37+
If you need to resolve external references in advance (for distribution or
38+
analysis), look at the [`jsonschema
39+
bundle`](https://github.com/sourcemeta/jsonschema/blob/main/docs/bundle.markdown)
40+
command.
4841

49-
{{<instance-fail `A string is not an integer`>}}
50-
{ "age": "some_string" }
51-
{{</instance-fail>}}
42+
{{</best-practice>}}
5243

53-
{{<schema `Schema for product data`>}}
54-
{
55-
"type": "array",
56-
"minItems": 1,
57-
"items": { "$ref": "#/$defs/product" },
58-
"$defs": {
59-
"product": {
60-
"type": "object",
61-
"properties": {
62-
"name": { "type": "string" },
63-
"price": { "type": "number", "minimum": 0 }
64-
}
65-
}
66-
}
67-
}
68-
{{</schema>}}
44+
{{<common-pitfall>}}
6945

70-
{{<instance-pass `The instance has a valid array of objects with product data as described in the "/$defs/product" subschema`>}}
71-
[
72-
{ "name": "T-shirt", "price": 19.99 },
73-
{ "name": "Mug", "price": 8.50 }
74-
]
46+
This keyword declares helper schemas for use _within_ the same schema file or
47+
resource. Defining schema files or resources that use this keyword (and
48+
typically no other keyword) to group common definitions for _other_ schema
49+
files or resources to reference is considered to be an anti-pattern. If you
50+
want to share a schema across multiple schema files or resources, that common
51+
schema should be a standalone schema file or resource itself.
7552

76-
{{</instance-pass>}}
53+
{{</common-pitfall>}}
7754

78-
{{<instance-fail `The array is empty, violating the "minItems" constraint requiring at least one product`>}}
79-
[]
80-
{{</instance-fail>}}
55+
## Examples
8156

82-
{{<schema `Schema for book details`>}}
57+
{{<schema `A schema that declares a helper schema to reduce duplication when defining multiple properties`>}}
8358
{
8459
"$schema": "https://json-schema.org/draft/2020-12/schema",
85-
"$id": "https://example.com/books",
86-
"type": "object",
8760
"properties": {
88-
"title": { "type": "string" },
89-
"author": { "$ref": "#author" }
61+
"firstName": { "$ref": "#/$defs/nonEmptyString" },
62+
"lastName": { "$ref": "#/$defs/nonEmptyString" }
9063
},
91-
"required": [ "title", "author" ],
9264
"$defs": {
93-
"author": {
94-
"$anchor": "author",
95-
"type": "object",
96-
"properties": {
97-
"name": { "type": "string" },
98-
"age": { "type": "integer" }
99-
}
65+
"nonEmptyString": {
66+
"type": "string",
67+
"minLength": 1
10068
}
10169
}
10270
}
10371
{{</schema>}}
10472

105-
{{<instance-pass `Instance with the required properties is valid`>}}
106-
{
107-
"title": "Fundamental Physics",
108-
"author": {
109-
"name": "John Doe",
110-
"age": 55
111-
}
112-
}
73+
74+
{{<instance-pass `An object value with non-empty first and last names is valid`>}}
75+
{ "firstName": "John", "lastName": "Doe" }
11376
{{</instance-pass>}}
11477

115-
{{<instance-fail `'author' proeprty is required`>}}
116-
{
117-
"title": "Fundamental Chemistry"
118-
}
78+
{{<instance-fail `An object value with empty first and last names is invalid`>}}
79+
{ "firstName": "", "lastName": "" }
11980
{{</instance-fail>}}
120-
121-
- _**Note**: JSON Pointer isn't the only way of accessing a subschema. You can also use the `$anchor` keyword to reference a subschema within `$defs`._

0 commit comments

Comments
 (0)