Skip to content

Commit dee6e69

Browse files
committed
Address lavalamp feedback
1 parent 85c40c0 commit dee6e69

File tree

1 file changed

+25
-19
lines changed
  • keps/sig-api-machinery/1027-api-unions

1 file changed

+25
-19
lines changed

keps/sig-api-machinery/1027-api-unions/README.md

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ become possible.
121121
### Goals
122122

123123
Provide a simple mechanism for API authors to label fields of a resource as
124-
members of a oneOf, in order to receive standardized:
124+
members of a oneOf, in order to receive standardized validation and
125+
normalization, rather than having to author it themeselves per
126+
resource as currently done as a workaround in various validation
127+
functions (e.g. `pkg/apis/<group>/validation/validation.go`).
125128

126129
* Validation - ensuring only one member field is set (or at most one if
127130
desired).
@@ -151,7 +154,7 @@ bogged down.
151154

152155
#### Story 1
153156

154-
As a CRD owner, I can use simple semantics (such as go tags), to express the
157+
As a CRD owner, I can use simple semantics (such as openapi tags/go markers), to express the
155158
desired validation of a oneOf (at most one or exactly one field may be set), and
156159
the API server will perform this validation automatically.
157160

@@ -206,16 +209,17 @@ added field to the union (due to version skew).
206209
We present a [guide doc](https://docs.google.com/document/d/1Wruosjo0ELLl1yxauzpsUjgH2fK9KdgXDmOdJ5sG7Kg/edit?resourcekey=0-8Pwzx6EvsFR7VQoXzCTY4Q) on how to interpret the test matrix, but the major
207210
conclusions are as follows (along with the test case number from the test matrix):
208211

209-
* (Case #22 and #27) If an unstructured client is unaware of field on the union, but wants to clear
212+
* (Case #22 and #27) If an unstructured client (i.e. a client that represents data as raw json maps with no knowledge of the schema)
213+
is unaware of field on the union, but wants to clear
210214
the union entirely (assuming the union is optional), it will have no way of doing
211215
so without a discriminator. With a discriminator, the client can express its
212216
intention by setting the discriminator to the empty value and the server can
213-
respects it intentions and clear any fields the client is unaware of.
217+
respect its intentions and clear any fields the client is unaware of.
214218
* (Case #12 and #16) If a structured client is unaware of a field in the union that is set and it
215219
just wants to echo back the union it received in a get request (such as when
216220
updating other parts of the object), a client without a discriminator will
217221
silently drop the currently set field, while a client with the discriminator
218-
will not change the discriminator value, indicating to the client that no
222+
will not change the discriminator value, indicating to the server that no
219223
changes are desired in the union.
220224
* (Case #34 and #39) If a client sets a union field that the server is not aware of, the server
221225
will silently drop it and attempt to clear the object of the union field. With
@@ -227,7 +231,7 @@ conclusions are as follows (along with the test case number from the test matrix
227231
logic to detect that the previously set field has not been modified and that
228232
only one of the other union fields has been.
229233

230-
### Go tags
234+
### Go Markers
231235

232236
We're proposing a new type of tags for go types (in-tree types, and also
233237
kubebuilder types):
@@ -236,15 +240,16 @@ kubebuilder types):
236240
- `// +unionDiscriminator` before a field means that this field is the
237241
discriminator for the union. This field MUST be a string. This field MUST be
238242
required.
239-
- `// +unionAllowEmpty` before a discriminator field means that by setting the
243+
- `// +unionOptional` before a discriminator field means that by setting the
240244
discriminator to an empty string, none of the union fields are persisted
241245
(meaning at most one member of the union must be set). If not present on the
242246
discriminator, exactly one of the union members must be set in order to be
243247
valid.
244-
- `// +unionMember=<discriminatorName>` before a field means that this
245-
field is a member of a union. The `<discriminatorName>` is optional if there
248+
- `// +unionMember=<memberName>,discriminatedBy=<discriminatorName>` before a field means that this
249+
field is a member of a union. The `<memberName>` is the name of the field that must be set as the discriminator value. It defaults to the json representation of the field name if not specified. The `<discriminatorName>` is optional if there
246250
is only union in a struct and required if there are multiple unions per
247-
struct.
251+
struct. It should be the json representation of the field tagged with
252+
`unionDiscriminator`.
248253

249254
Note unions can't span across multiple go structures (all the fields that are part of a union has to be together in the
250255
same structure), examples of what is allowed:
@@ -272,15 +277,17 @@ type Union struct {
272277
FieldB int `json:"fieldB"`
273278
}
274279
275-
// This generates two unions, each with two fields and a discriminator. The
280+
// This will generate one union that can be embedded because the members explicitly define their discriminator.
281+
// Also, the unionMember markers here demonstrate how to customize the names used for
282+
each field in the discriminator.
276283
type Union2 struct {
277284
// +unionDiscriminator
278285
// +required
279286
Type string `json:"type"`
280-
// +unionMember=type
287+
// +unionMember=ALPHA,discriminatedBy=type
281288
// +optional
282289
Alpha int `json:"alpha"`
283-
// +unionMember=type
290+
// +unionMember=BETA,discriminatedBy=type
284291
// +optional
285292
Beta int `json:"beta"`
286293
}
@@ -294,10 +301,10 @@ type InlinedUnion struct {
294301
// +unionAllowEmpty
295302
// +required
296303
FieldType string `json:"fieldType"`
297-
// +unionMember=fieldType
304+
// +unionMember,discriminatedBy=fieldType
298305
// +optional
299306
Field1 *int `json:"field1,omitempty"`
300-
// +unionMember=fieldType
307+
// +unionMember,discriminatedBy=fieldType
301308
// +optional
302309
Field2 *int `json:"field2,omitempty"`
303310
@@ -337,16 +344,15 @@ Issues primarily arise here because of version skew between a client and a serve
337344
such as when a client is unaware of new fields added to a union and thus doesn't
338345
know how to clear these new fields when trying to set a different field.
339346

340-
For unions with a discriminator (all newly created unions and some existing
341-
unions), normalization is simple: the server should always respect the
347+
For unions with a discriminator, normalization is simple: the server should always respect the
342348
discriminator.
343349

344350
This means two things:
345351
1. when the server receives a request with a discriminator set to a
346352
given field, it should clear out any other fields that are set.
347353
2. when the server receives a request with a discriminator set to a given field,
348-
but that given field is empty, it should maintain the value of the field that
349-
currently exists.
354+
but that given field is empty, the server should fail with a clear error
355+
message.
350356

351357
For situations where a typed client is unaware of a new field (that is currently
352358
set) and drops the set field such that no fields are now set, the server will

0 commit comments

Comments
 (0)