You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: contributors/devel/sig-architecture/api-conventions.md
+54-24Lines changed: 54 additions & 24 deletions
Original file line number
Diff line number
Diff line change
@@ -822,50 +822,80 @@ indicated in the Retry-After header, if it is present).
822
822
823
823
Fields must be either optional or required.
824
824
825
+
A field that is required means that the writer must express an opinion about the value of the field.
826
+
Required fields are always present, and readers can rely on the field being present in the object.
827
+
828
+
An optional field is one where the writer may choose to omit the field entirely.
829
+
Readers should not assume that the field is present, unless the field also has a server-side default value.
830
+
831
+
Default values can only be set on optional fields.
832
+
825
833
Optional fields have the following properties:
826
834
827
835
- They have the `+optional` comment tag in Go.
828
836
- They are a pointer type in the Go definition (e.g. `AwesomeFlag *SomeFlag`) or
829
837
have a built-in `nil` value (e.g. maps and slices).
838
+
- They are marked with the `omitempty` json struct tag in the Go definition.
830
839
- The API server should allow POSTing and PUTing a resource with this field
831
840
unset.
832
841
833
-
In most cases, optional fields should also have the `omitempty` struct tag (the
834
-
`omitempty`option specifies that the field should be omitted from the json
835
-
encoding if the field has an empty value). However, If you want to have
836
-
different logic for an optional field which is not provided vs. provided with
837
-
empty values, do not use `omitempty` (e.g. https://github.com/kubernetes/kubernetes/issues/34641).
842
+
When the field type has a built-in `nil` value, such as a map or a slice, and
843
+
your use case means that you need to be able to distinguish between
844
+
"field not set"and "field set to an empty value", you should use a pointer to
845
+
the type, even though it has a built-in `nil` value.
846
+
See https://github.com/kubernetes/kubernetes/issues/34641.
838
847
839
848
Note that for backward compatibility, any field that has the `omitempty` struct
840
-
tag will be considered to be optional, but this may change in the future and
841
-
having the `+optional` comment tag is highly recommended.
849
+
tag, and is not explicitly marked as `+required`, will be considered to be optional.
850
+
This is expected to change in the future and having the `+optional` comment tag is
851
+
now required on new optional fields.
842
852
843
-
Required fields have the opposite properties, namely:
853
+
Required fields have the following properties:
844
854
845
855
- They do not have an `+optional` comment tag.
846
-
- They do not have an `omitempty` struct tag.
847
-
- They are not a pointer type in the Go definition (e.g. `AnotherFlag SomeFlag`).
856
+
- They mark themselves as required explicitly with a `+required` comment tag.
848
857
- The API server should not allow POSTing or PUTing a resource with this field
849
858
unset.
859
+
- They _typically_ do not use pointer types in the Go definition (e.g. `AnotherFlag SomeFlag`), though required fields where the zero value is a valid value must use pointer types, paired with an `omitempty` struct tag to avoid spurious null serializations.
860
+
861
+
For more details on how to use pointers and `omitempty` with fields, see [Serialization of optional/required fields](#serialization-of-optionalrequired-fields).
850
862
851
863
Using the `+optional` or the `omitempty` tag causes OpenAPI documentation to
852
864
reflect that the field is optional.
853
865
854
-
Using a pointer allows distinguishing unset from the zero value for that type.
855
-
There are some cases where, in principle, a pointer is not needed for an
856
-
optional field since the zero value is forbidden, and thus implies unset. There
857
-
are examples of this in the codebase. However:
858
-
859
-
- it can be difficult for implementors to anticipate all cases where an empty
860
-
value might need to be distinguished from a zero value
861
-
- structs are not omitted from encoder output even where omitempty is specified,
862
-
which is messy;
863
-
- having a pointer consistently imply optional is clearer for users of the Go
864
-
language client, and any other clients that use corresponding types
865
-
866
-
Therefore, we ask that pointers always be used with optional fields that do not
867
-
have a built-in `nil` value.
866
+
### Serialization of optional/required fields
868
867
868
+
Using a pointer allows distinguishing unset from the zero value for that type.
869
+
There are some cases where, in principle, a pointer is not needed for a
870
+
field since the zero value is forbidden, and thus implies unset.
871
+
There are examples of this in the codebase. However:
872
+
873
+
- It can be difficult for implementors to anticipate all cases where an empty
874
+
value might need to be distinguished from a zero value.
875
+
- Structs are not omitted from encoder output even where `omitempty` is specified,
876
+
which is messy.
877
+
878
+
To determine whether a field should be a pointer, consider the following:
879
+
880
+
```mermaid
881
+
graph TD;
882
+
A[Start] --> B{Is the zero value a valid user choice?};
883
+
B -- Yes --> C[Use a pointer and omitempty];
884
+
B -- No --> D{Is the field optional, or required?};
885
+
D -- Optional --> E[Does the field have a built-in nil value?];
886
+
E -- Yes --> F[Do not use a pointer, use omitempty];
887
+
E -- no --> C;
888
+
D -- Required --> F
889
+
```
890
+
There are several implications of the above:
891
+
- For lists and maps where the zero valid is a valid user choice, this means that `[]` and `{}` have a semantically different meaning than unset, in this case it is appropriate to use `*[]T` or `*map[T]S` respectively.
892
+
- For `bool` types, the zero value is `false`, which is always a valid user choice. `bool` types should always be pointers, and should always use the `omitempty` tag.
893
+
- When a field is required, and the zero value is not valid, a structured client who has not expressed an explicit choice will have their request rejected by the API server based on the invalid value, rather than the field being unset.
894
+
- For example, a string with a minimum length of 1; Validation would not understand if the field was unset, or set to the empty string deliberately, but would still reject the request because it did not meet the length requirements.
895
+
- Technically, using a pointer in these cases is also acceptable, but not advised as it makes coding more complex, and increases the risk of nil pointer exceptions.
896
+
- In these cases, not using `omitempty` provides the same result, but pollutes the marhsalled object with zero values and is not recommended.
897
+
- For structs, the zero value can only be valid when the struct has no required fields, and does not require at least one property to be set.
898
+
- Required structs should use `omitzero` to avoid marshalling the zero value.
0 commit comments