Skip to content

Commit 0cd16f7

Browse files
committed
Revise the writeOnly keyword
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 25e4ab0 commit 0cd16f7

File tree

2 files changed

+70
-48
lines changed

2 files changed

+70
-48
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ conditions determined by a dynamic operator like [`anyOf`]({{< ref
7171
{
7272
"$schema": "https://json-schema.org/draft/2020-12/schema",
7373
"properties": {
74-
"id": { "readOnly": true },
74+
"id": { "type": "integer", "readOnly": true },
7575
"value": { "type": "integer" }
7676
}
7777
}
@@ -97,7 +97,7 @@ conditions determined by a dynamic operator like [`anyOf`]({{< ref
9797
{
9898
"$schema": "https://json-schema.org/draft/2020-12/schema",
9999
"properties": {
100-
"id": true,
100+
"id": { "type": "integer" },
101101
"value": { "type": "integer" }
102102
},
103103
"dependentSchemas": {

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

Lines changed: 68 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,80 +28,102 @@ related:
2828
keyword: deprecated
2929
---
3030

31-
the `writeOnly` keyword is used to indicate that an instance value should be writable, but it won't be included when the instance is retrieved from the owning authority. It's important to note that this doesn't imply the schema itself is writable; schemas must be treated as immutable. Instead, the keyword specifies instances where read/write operation semantics are use case specific.
31+
The `writeOnly` keyword, when set to `true`, signifies that an instance value
32+
(such as a specific object property) can be modified or removed but not read,
33+
whatever that means in the context of the system. For example, form generators
34+
may rely on this keyword to mark the corresponding input as as a password
35+
field. This keyword does not affect validation, but the evaluator will collect
36+
its value as an annotation.
3237

33-
* `writeOnly` does not affect data validation but serves as an informative annotation.
38+
{{<best-practice>}}
3439

35-
## Examples
40+
Avoid setting this keyword to the default value `false`. If an instance value
41+
is not considered to be write only, the best practice is to omit the use of
42+
this keyword altogether. This prevents unnecessarily generating and collecting
43+
an annotation that does not carry any additional meaning.
3644

37-
{{<schema `Schema with 'writeOnly' keyword`>}}
38-
{
39-
"$schema": "https://json-schema.org/draft/2020-12/schema",
40-
"writeOnly": true,
41-
"type": "number"
42-
}
43-
{{</schema>}}
45+
Also avoid simultaneously setting this keyword and the [`readOnly`]({{< ref
46+
"2020-12/meta-data/readonly" >}}) keyword to `true` for the same instance
47+
location, resulting in ambiguous semantics.
4448

45-
{{<instance-pass `An instance with a numeric value is valid`>}}
46-
45
47-
{{</instance-pass>}}
49+
{{</best-practice>}}
4850

49-
{{<instance-annotation>}}
50-
{ "keyword": "/writeOnly", "instance": "", "value": true }
51-
{{</instance-annotation>}}
51+
{{<common-pitfall>}}
52+
53+
Tooling makers must be careful when statically traversing schemas in search of
54+
occurences of this keyword. It is possible for schemas to make use of this
55+
keyword behind conditional operators, references, or any other type of keyword
56+
that makes it hard or even impossible to correctly locate these values without
57+
fully evaluating the schema against an instance. The only bullet proof method
58+
is through annotation collection.
59+
60+
For example, an instance property might only be read only under certain
61+
conditions determined by a dynamic operator like [`anyOf`]({{< ref
62+
"2020-12/applicator/anyof" >}}).
63+
64+
{{</common-pitfall>}}
65+
66+
{{<metaschema-check-type `boolean`>}}
5267

53-
{{<schema `Schema with logical operators`>}}
68+
## Examples
69+
70+
{{<schema `A schema that statically marks the password optional object property as write only`>}}
5471
{
5572
"$schema": "https://json-schema.org/draft/2020-12/schema",
56-
"if": {
57-
"properties": {
58-
"sensitive": { "const": true }
59-
}
60-
},
61-
"then": {
62-
"writeOnly": true
63-
},
64-
"else": {
65-
"writeOnly": false
73+
"properties": {
74+
"username": { "type": "string" }
75+
"password": { "type": "string", "writeOnly": true },
6676
}
6777
}
6878
{{</schema>}}
6979

70-
{{<instance-pass>}}
71-
{ "sensitive": false }
80+
{{<instance-pass `An object value that defines the write only property is valid but an annotation is emitted`>}}
81+
{ "username": "jviotti", "password": "mysupersecretpassword" }
7282
{{</instance-pass>}}
7383

7484
{{<instance-annotation>}}
75-
{ "keyword": "/else/writeOnly", "instance": "", "value": false }
85+
{ "keyword": "/properties/password/writeOnly", "instance": "/password", "value": true }
7686
{{</instance-annotation>}}
7787

78-
{{<instance-pass>}}
79-
{ "sensitive": true }
88+
{{<instance-pass `An object value that does not define the write only property is valid and no annotation is emitted`>}}
89+
{ "username": "jviotti" }
8090
{{</instance-pass>}}
8191

82-
{{<instance-annotation>}}
83-
{ "keyword": "/then/writeOnly", "instance": "", "value": true }
84-
{{</instance-annotation>}}
92+
{{<instance-fail `An object value that does not match the schema is invalid and no annotations are emitted`>}}
93+
{ "password": null }
94+
{{</instance-fail>}}
8595

86-
{{<schema `Schema with multiple annotations for the same instance`>}}
96+
{{<schema `A schema that dynamically marks the password optional object property as write only based on the presence of the username property`>}}
8797
{
8898
"$schema": "https://json-schema.org/draft/2020-12/schema",
89-
"writeOnly": true,
90-
"$ref": "#/$defs/name",
91-
"$defs": {
92-
"name": {
93-
"writeOnly": true,
94-
"type": "string"
99+
"properties": {
100+
"username": { "type": "string" }
101+
"password": { "type": "string" },
102+
}
103+
"dependentSchemas": {
104+
"username": {
105+
"properties": { "password": { "writeOnly": true } }
95106
}
96107
}
97108
}
98109
{{</schema>}}
99110

100-
{{<instance-pass>}}
101-
"John Doe"
111+
{{<instance-pass `An object value that defines both properties is valid but an annotation is emitted`>}}
112+
{ "username": "jviotti", "password": "mysupersecretpassword" }
102113
{{</instance-pass>}}
103114

104115
{{<instance-annotation>}}
105-
{ "keyword": "/writeOnly", "instance": "", "value": true }
106-
{ "keyword": "/$ref/writeOnly", "instance": "", "value": true }
116+
{ "keyword": "/dependentSchemas/username/properties/password/writeOnly", "instance": "/password", "value": true }
107117
{{</instance-annotation>}}
118+
119+
{{<instance-pass `An object value that only defines the username property is valid and no annotation is emitted`>}}
120+
{ "username": "jviotti" }
121+
{{</instance-pass>}}
122+
123+
{{<instance-pass `An object value that only defines the password property is valid and no annotation is emitted`>}}
124+
{ "password": "mysupersecretpassword" }
125+
{{</instance-pass>}}
126+
127+
{{<instance-fail `An object value that does not match the schema is invalid and no annotations are emitted`>}}
128+
{ "password": null }
129+
{{</instance-fail>}}

0 commit comments

Comments
 (0)