Repository: danielgtaylor/huma
Pull request #527 (2024-07-29 13:39:10)

fix: nullable schemas for arrays/slices
Hi, this is a small fix regarding the schema generation for array/slices. 

Since `json.Marshal` yields `null` values for empty slices (see #457), this outcome should be explicit in the schema :slightly_smiling_face: 



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
	- Enhanced schema generation to allow nullable items within arrays.
	- Updated schema definitions to reflect arrays that can contain null values.

- **Bug Fixes**
	- Improved test cases to ensure consistent handling of nullable array types in JSON schema definitions.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Patch:
diff --git a/schema.go b/schema.go
index e17eeb9..bfbc33a 100644
--- a/schema.go
+++ b/schema.go
@@ -746,6 +746,7 @@ func schemaFromType(r Registry, t reflect.Type) *Schema {
 			s.ContentEncoding = "base64"
 		} else {
 			s.Type = TypeArray
+			s.Nullable = true
 			s.Items = r.Schema(t.Elem(), true, t.Name()+"Item")
 
 			if t.Kind() == reflect.Array {


Test patch:
diff --git a/schema_test.go b/schema_test.go
index e717c4a..21ae26f 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -204,12 +204,12 @@ func TestSchema(t *testing.T) {
 		{
 			name:     "array",
 			input:    [2]int{1, 2},
-			expected: `{"type": "array", "items": {"type": "integer", "format": "int64"}, "minItems": 2, "maxItems": 2}`,
+			expected: `{"type": ["array", "null"], "items": {"type": "integer", "format": "int64"}, "minItems": 2, "maxItems": 2}`,
 		},
 		{
 			name:     "slice",
 			input:    []int{1, 2, 3},
-			expected: `{"type": "array", "items": {"type": "integer", "format": "int64"}}`,
+			expected: `{"type": ["array", "null"], "items": {"type": "integer", "format": "int64"}}`,
 		},
 		{
 			name:     "map",
@@ -285,7 +285,7 @@ func TestSchema(t *testing.T) {
 				"type": "object",
 				"properties": {
 					"value": {
-						"type": "array",
+						"type": ["array", "null"],
 						"minItems": 1,
 						"maxItems": 10,
 						"uniqueItems": true,
@@ -343,7 +343,7 @@ func TestSchema(t *testing.T) {
 				"type": "object",
 				"properties": {
 					"value": {
-						"type": "array",
+						"type": ["array", "null"],
 						"items": {
 							"type": "integer",
 							"format": "int64",
@@ -433,7 +433,7 @@ func TestSchema(t *testing.T) {
 				"type": "object",
 				"properties": {
 					"value": {
-						"type": "array",
+						"type": ["array", "null"],
 						"items": {
 							"type": "string"
 						},
@@ -453,7 +453,7 @@ func TestSchema(t *testing.T) {
 				"type": "object",
 				"properties": {
 					"value": {
-						"type": "array",
+						"type": ["array", "null"],
 						"items": {
 							"type": "integer",
 							"format": "int64"
@@ -744,7 +744,7 @@ func TestSchema(t *testing.T) {
 						},
 						"maxItems":1,
 						"minItems":1,
-						"type":"array"
+						"type":["array", "null"]
 					},
 					"byRef":{
 						"$ref":"#/components/schemas/RecursiveChildKey"
@@ -762,7 +762,7 @@ func TestSchema(t *testing.T) {
 						"items":{
 							"$ref":"#/components/schemas/RecursiveChildLoop"
 						},
-						"type":"array"}
+						"type":["array", "null"]}
 					},
 					"required":["slice","array","map","byValue", "byRef"],
 					"type":"object"
@@ -884,7 +884,7 @@ func TestSchema(t *testing.T) {
 				"additionalProperties":false,
 				"properties":{
 					"values":{
-						"type":"array",
+						"type":["array", "null"],
 						"items":{
 							"type":"string",
 							"minLength":1,
@@ -1041,7 +1041,7 @@ func TestSchema(t *testing.T) {
 						},
 						"maxItems":4,
 						"minItems":4,
-						"type":"array"
+						"type":["array", "null"]
 					}
 				},
 				"required":["value"],
@@ -1064,7 +1064,7 @@ func TestSchema(t *testing.T) {
 						},
 						"maxItems":4,
 						"minItems":4,
-						"type":"array"
+						"type":["array", "null"]
 					}
 				},
 				"required":["value"],