Skip to content

Commit d88e948

Browse files
committed
Improve the default keyword
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 872d50d commit d88e948

File tree

3 files changed

+91
-67
lines changed

3 files changed

+91
-67
lines changed

content/2020-12/meta-data/default.markdown

Lines changed: 87 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -28,97 +28,121 @@ related:
2828
keyword: deprecated
2929
---
3030

31-
The `default` keyword in JSON Schema is used to specify a default value for an instance. This value is not automatically used to fill in missing values during the validation process but can be used by tools such as documentation or form generators.
31+
The `default` keyword declares a default instance value for a schema or any of
32+
its subschemas, typically to support specialised tooling like documentation and
33+
form generators. This keyword does not affect validation, but the evaluator
34+
will collect its value as an annotation.
3235

33-
_**Note:** While it is recommended that the default value validate against its subschema, this requirement is not strictly enforced._
36+
{{<common-pitfall>}}
37+
38+
The standard evaluation process will not automatically use these values to fill
39+
in missing parts of the instance. Furthermore, the JSON Schema specification
40+
does not provide any guidance on how this keyword should be used.
41+
42+
Consult the documentation of any JSON Schema tooling you rely on to check if
43+
and how it makes use of this keyword.
44+
45+
{{</common-pitfall>}}
46+
47+
{{<best-practice>}}
48+
49+
Meta-schema validation will not check that the default values you declare are
50+
actually valid against their respective schemas, as JSON Schema does not offer
51+
a mechanism for meta-schemas to declare that instances validate against parts
52+
of the same instance being evaluated. As a consequence, it is not rare for
53+
schemas to declare invalid default values that go undetected for a long time.
54+
55+
It is recommended to use the [`jsonschema
56+
lint`](https://github.com/sourcemeta/jsonschema/blob/main/docs/lint.markdown)
57+
command, as this linter performs further checks to detect many corner cases,
58+
including this one.
59+
60+
{{</best-practice>}}
61+
62+
{{<learning-more>}}
63+
64+
You might be tempted to evaluate a schema against an instance and rely on
65+
`default` annotations to feed back the missing values back to it. However,
66+
there is a known limitation that prevents this approach: in JSON Schema,
67+
annotations are collected when a subschema is evaluated, which means that the
68+
default value annotation is only emitted when the corresponding instance
69+
location is present (and thus a default value is not required).
70+
71+
There is a
72+
[discussion](https://github.com/json-schema-org/json-schema-spec/issues/867) to
73+
introduce new variants of this keyword (`propertyDefaults` and `itemDefaults`)
74+
to properly support this use case.
75+
76+
{{</learning-more>}}
3477

3578
## Examples
3679

37-
{{<schema `Schema with 'default' keyword`>}}
80+
{{<schema `A schema that declares top level and nested default values`>}}
3881
{
3982
"$schema": "https://json-schema.org/draft/2020-12/schema",
40-
"default": "John",
41-
"type": "number"
83+
"type": "object",
84+
"default": {},
85+
"properties": {
86+
"language": { "default": "en" },
87+
"notifications": { "default": true }
88+
}
4289
}
4390
{{</schema>}}
4491

45-
{{<instance-pass `An instance with a numeric value is valid`>}}
46-
45
92+
{{<instance-pass `An object value that defines both properties is valid and annotations are emitted`>}}
93+
{ "language": "es", "notifications": false }
4794
{{</instance-pass>}}
4895

4996
{{<instance-annotation>}}
50-
{ "keyword": "/default", "instance": "", "value": "John" }
97+
{ "keyword": "/default", "instance": "", "value": {} }
98+
{ "keyword": "/properties/language/default", "instance": "/language", "value": "en" }
99+
{ "keyword": "/properties/notifications/default", "instance": "/notifications", "value": true }
51100
{{</instance-annotation>}}
52101

53-
{{<schema `Schema with logical operators`>}}
54-
{
55-
"$schema": "https://json-schema.org/draft/2020-12/schema",
56-
"properties": {
57-
"name": { "type": "string", "default": "John" },
58-
"qualification": {
59-
"enum": [ "degree", "diploma" ],
60-
"default": "diploma"
61-
}
62-
},
63-
"if": {
64-
"properties": {
65-
"qualification": { "const": "degree" }
66-
}
67-
},
68-
"then": {
69-
"properties": {
70-
"degreeCertificate": {
71-
"type": "string",
72-
"default": "B0B8RKEZ90"
73-
}
74-
},
75-
"required": [ "degreeCertificate" ]
76-
},
77-
"else": {
78-
"properties": {
79-
"diplomaCertificate": {
80-
"type": "string",
81-
"default": "PW458C468E"
82-
}
83-
},
84-
"required": [ "diplomaCertificate" ]
85-
}
86-
}
87-
{{</schema>}}
88-
89-
{{<instance-pass `An instance conforming to the schema is valid`>}}
90-
{
91-
"name": "Doe",
92-
"qualification": "degree",
93-
"degreeCertificate": "O5CYPZACTN"
94-
}
102+
{{<instance-pass `An object value that omits both properties is valid but their default values are (perhaps counter-intuitively) not emitted`>}}
103+
{}
95104
{{</instance-pass>}}
96105

97106
{{<instance-annotation>}}
98-
{ "keyword": "/properties/name/default", "instance": "/name", "value": "John" }
99-
{ "keyword": "/properties/qualification/default", "instance": "/qualification", "value": "diploma" }
100-
{ "keyword": "/then/properties/degreeCertificate/default", "instance": "/degreeCertificate", "value": "B0B8RKEZ90" }
107+
{ "keyword": "/default", "instance": "", "value": {} }
101108
{{</instance-annotation>}}
102109

103-
{{<schema `Schema with multiple annotations for the same instance`>}}
110+
{{<instance-fail `A non-object value is invalid and no annotations are emitted`>}}
111+
"Hello World"
112+
{{</instance-fail>}}
113+
114+
{{<schema `A schema that declares multiple default values for the same instance location`>}}
104115
{
105116
"$schema": "https://json-schema.org/draft/2020-12/schema",
106-
"default": "John",
107-
"$ref": "#/$defs/name",
117+
"properties": {
118+
"email": {
119+
"default": "johndoe@acme.com",
120+
"$ref": "#/$defs/email-address"
121+
}
122+
},
108123
"$defs": {
109-
"name": {
110-
"default": "John",
111-
"type": "string"
124+
"email-address": {
125+
"type": "string",
126+
"format": "email",
127+
"default": "example@example.org"
112128
}
113129
}
114130
}
115131
{{</schema>}}
116132

117-
{{<instance-pass `A string instance is valid`>}}
118-
"Doe"
133+
{{<instance-pass `An object value that defines an email property is valid and both annotations are emitted`>}}
134+
{ "email": "jane@foo.com" }
119135
{{</instance-pass>}}
120136

121137
{{<instance-annotation>}}
122-
{ "keyword": "/default", "instance": "", "value": "John" }
123-
{ "keyword": "/$ref/default", "instance": "", "value": "John" }
138+
{ "keyword": "/properties/email/default", "instance": "/email", "value": "johndoe@acme.com" }
139+
{ "keyword": "/$defs/email-address/default", "instance": "/email", "value": "example@example.org" }
124140
{{</instance-annotation>}}
141+
142+
{{<instance-pass `An object value that omits the email property is valid but the default values are (perhaps counter-intuitively) not emitted`>}}
143+
{}
144+
{{</instance-pass>}}
145+
146+
{{<instance-fail `An object value with a non-string email property is invalid and no annotations are emitted`>}}
147+
{ "email": 1 }
148+
{{</instance-fail>}}

content/2020-12/meta-data/description.markdown

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ is through annotation collection.
7777
{ "keyword": "/description", "instance": "", "value": "This schema describes an even number" }
7878
{{</instance-annotation>}}
7979

80-
{{<instance-fail `An odd number value is invalid no annotations are emitted`>}}
80+
{{<instance-fail `An odd number value is invalid and no annotations are emitted`>}}
8181
7
8282
{{</instance-fail>}}
8383

@@ -110,6 +110,6 @@ is through annotation collection.
110110
{ "keyword": "/else/description", "instance": "", "value": "This is an odd number" }
111111
{{</instance-annotation>}}
112112

113-
{{<instance-fail `A non-number value is invalid no annotations are emitted`>}}
113+
{{<instance-fail `A non-number value is invalid and no annotations are emitted`>}}
114114
"Hello World"
115115
{{</instance-fail>}}

content/2020-12/meta-data/title.markdown

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ is through annotation collection.
7979
{ "keyword": "/title", "instance": "", "value": "Even number" }
8080
{{</instance-annotation>}}
8181

82-
{{<instance-fail `An odd number value is invalid no annotations are emitted`>}}
82+
{{<instance-fail `An odd number value is invalid and no annotations are emitted`>}}
8383
7
8484
{{</instance-fail>}}
8585

@@ -112,6 +112,6 @@ is through annotation collection.
112112
{ "keyword": "/else/title", "instance": "", "value": "Odd Number" }
113113
{{</instance-annotation>}}
114114

115-
{{<instance-fail `A non-number value is invalid no annotations are emitted`>}}
115+
{{<instance-fail `A non-number value is invalid and no annotations are emitted`>}}
116116
"Hello World"
117117
{{</instance-fail>}}

0 commit comments

Comments
 (0)