Repository: danielgtaylor/huma
Pull request #742 (2025-02-26 14:20:02)

Add 'omitzero' support to mark optional fields
Add support for using the new `omitzero` field tag introduced in go-1.24 to mark those fields as optional/not-required

https://tip.golang.org/doc/go1.24#encodingjsonpkgencodingjson
> When marshaling, a struct field with the new omitzero option in the struct field tag will be omitted if its value is zero.

### Changes
- Added a new check for `omitzero` to mark field as optional in `schema.go`
- Added new tests in to check `omitempty` and `omitzero` in `schema_test.go`
- Mentioned the new tag in `request-validation.md` docs

Lmk if there are other files/places that need changing for this change. 


Patch:
diff --git a/docs/docs/features/request-validation.md b/docs/docs/features/request-validation.md
index 65f2a86..0755275 100644
--- a/docs/docs/features/request-validation.md
+++ b/docs/docs/features/request-validation.md
@@ -25,8 +25,9 @@ Fields being optional/required is determined automatically but can be overridden
 
 1. Start with all fields required.
 2. If a field has `omitempty`, it is optional.
-3. If a field has `required:"false"`, it is optional.
-4. If a field has `required:"true"`, it is required.
+3. If a field has `omitzero`, it is optional.
+4. If a field has `required:"false"`, it is optional.
+5. If a field has `required:"true"`, it is required.
 
 Pointers have no effect on optional/required. The same rules apply regardless of whether the struct is being used for request input or response output. Some examples:
 
@@ -39,8 +40,10 @@ type MyStruct struct {
 
     // The following are all optional.
     Optional1 string  `json:"optional1,omitempty"`
-    Optional2 *string `json:"optional2,omitempty"`
-    Optional3 string  `json:"optional3" required:"false"`
+    Optional2 string  `json:"optional2,omitzero"`
+    Optional3 *string `json:"optional3,omitempty"`
+    Optional4 *string `json:"optional4,omitempty,omitzero"`
+    Optional5 string  `json:"optional5" required:"false"`
 }
 ```
 
diff --git a/schema.go b/schema.go
index f499d9e..19a44e4 100644
--- a/schema.go
+++ b/schema.go
@@ -816,8 +816,9 @@ func schemaFromType(r Registry, t reflect.Type) *Schema {
 			fieldSet[f.Name] = struct{}{}
 
 			// Controls whether the field is required or not. All fields start as
-			// required, then can be made optional with the `omitempty` JSON tag or it
-			// can be overridden manually via the `required` tag.
+			// required, then can be made optional with the `omitempty` JSON tag,
+			// `omitzero` JSON tag, or it can be overridden manually via the
+			// `required` tag.
 			fieldRequired := true
 
 			name := f.Name
@@ -828,6 +829,9 @@ func schemaFromType(r Registry, t reflect.Type) *Schema {
 				if strings.Contains(j, "omitempty") {
 					fieldRequired = false
 				}
+				if strings.Contains(j, "omitzero") {
+					fieldRequired = false
+				}
 			}
 			if name == "-" {
 				// This field is deliberately ignored.


Test patch:
diff --git a/schema_test.go b/schema_test.go
index e3e671f..18ab17a 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -499,6 +499,36 @@ func TestSchema(t *testing.T) {
 				"additionalProperties": false
 			}`,
 		},
+		{
+			name: "field-optional-with-omitempty",
+			input: struct {
+				Value string `json:"value,omitempty"`
+			}{},
+			expected: `{
+				"type": "object",
+				"properties": {
+					"value": {
+						"type": "string"
+					}
+				},
+				"additionalProperties": false
+			}`,
+		},
+		{
+			name: "field-optional-with-omitzero",
+			input: struct {
+				Value string `json:"value,omitzero"`
+			}{},
+			expected: `{
+				"type": "object",
+				"properties": {
+					"value": {
+						"type": "string"
+					}
+				},
+				"additionalProperties": false
+			}`,
+		},
 		{
 			name: "field-example-custom",
 			input: struct {