Skip to content

Commit

Permalink
Merge pull request #256 from danielgtaylor/object-addlprops
Browse files Browse the repository at this point in the history
feat: better control over object additionalProperties
  • Loading branch information
danielgtaylor authored Feb 20, 2024
2 parents e99f2bd + c475605 commit 15f15fe
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
27 changes: 26 additions & 1 deletion docs/docs/features/request-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ description: Built-in JSON Schema validation rules for request parameters and bo

## Request Validation { .hidden }

Go struct tags are used to annotate inputs/output structs with information that gets turned into [JSON Schema](https://json-schema.org/) for documentation and validation.
Go struct tags are used to annotate inputs/output structs with information that gets turned into [JSON Schema](https://json-schema.org/) for documentation and validation. For example:

```go title="code.go"
type Person struct {
Name string `json:"name" doc:"Person's name" minLength:"1" maxLength:"80"`
Age uint `json:"age,omitempty" doc:"Person's age" maximum:"120"`
}
```

The standard `json` tag is supported and can be used to rename a field and mark fields as optional using `omitempty`. The following additional tags are supported on model fields:

Expand Down Expand Up @@ -40,6 +47,24 @@ Parameters have some additional validation tags:
| -------- | --------------------------------- | --------------- |
| `hidden` | Hide parameter from documentation | `hidden:"true"` |

## Strict vs. Loose Field Validation

By default, Huma is strict about which fields are allowed in an object, making use of the `additionalProperties: false` JSON Schema setting. This means if a client sends a field that is not defined in the schema, the request will be rejected with an error. This can help to prevent typos and other issues and is recommended for most APIs.

If you need to allow additional fields, for example when using a third-party service which will call your system and you only care about a few fields, you can use the `additionalProperties:"true"` field tag on the struct by assigning it to a dummy `_` field.

```go title="code.go"
type PartialInput struct {
_ struct{} `json:"-" additionalProperties:"true"`
Field1 string `json:"field1"`
Field2 bool `json:"field2"`
}
```

!!! info "Note"

The use of `struct{}` is optional but efficient. It is used to avoid allocating memory for the dummy field as an empty object requires no space.

## Advanced Validation

When using custom JSON Schemas, i.e. not generated from Go structs, it's possible to utilize a few more validation rules. The following schema fields are respected by the built-in validator:
Expand Down
10 changes: 9 additions & 1 deletion schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,15 @@ func SchemaFromType(r Registry, t reflect.Type) *Schema {
}
}
s.Type = TypeObject
s.AdditionalProperties = false

additionalProps := false
if f, ok := t.FieldByName("_"); ok {
if _, ok := f.Tag.Lookup("additionalProperties"); ok {
additionalProps = boolTag(f, "additionalProperties")
}
}
s.AdditionalProperties = additionalProps

s.Properties = props
s.propertyNames = propNames
s.Required = required
Expand Down
17 changes: 17 additions & 0 deletions schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,23 @@ func TestSchema(t *testing.T) {
input: map[string]string{"foo": "bar"},
expected: `{"type": "object", "additionalProperties": {"type": "string"}}`,
},
{
name: "additionalProps",
input: struct {
_ struct{} `json:"-" additionalProperties:"true"`
Value string `json:"value"`
}{},
expected: `{
"type": "object",
"properties": {
"value": {
"type": "string"
}
},
"required": ["value"],
"additionalProperties": true
}`,
},
{
name: "field-int",
input: struct {
Expand Down

0 comments on commit 15f15fe

Please sign in to comment.