danielgtaylor / danielgtaylor/huma
SkipValidateBody/SkipValidateParams not being propagated through UseModifier and OnAddOperation
- Dominant language
- Go
- Stars
- 4.4k
- Forks
- 285
- Avg merge
- 40m
- Merged PRs (30d)
- 1
Description
# Description
I want to opt-out from `ModelValidator` to use an alternative approach to handle validation and error responses.
The API provide some ways to intercept Operations to modify them:
- `(*huma.Group).UseModifier(modifier func(o *huma.Operation, next func(*huma.Operation))`
- `(huma.Config).OnAddOperation []huma.OnAddFunc`
But none of them propagates the `SkipValidateBody/SkipValidateParams` accordingly.
# Reproduction
**Step 1**: Setup the HTTP API with all possible Operation interceptors to set `SkipValidateBody` and/or `SkipValidateParams` to `true` (this operation should be idempotent, so I included all possible interceptions in the same example).
```go
package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/danielgtaylor/huma/v2"
"github.com/danielgtaylor/huma/v2/adapters/humago"
)
type Enum string
func (Enum) TransformSchema(r huma.Registry, s *huma.Schema) *huma.Schema {
s.Type = huma.TypeString
s.Enum = []any{"foo", "bar"}
return s
}
func main() {
cfg := huma.DefaultConfig("Huma Test", "1.0.0")
cfg.OnAddOperation = append(cfg.OnAddOperation, func(oapi *huma.OpenAPI, op *huma.Operation) {
// First attempt to skip validation, globally.
op.SkipValidateBody = true
op.SkipValidateParams = true
})
mux := http.NewServeMux()
api := humago.New(mux, cfg)
group := huma.NewGroup(api, "/group")
group.UseModifier(func(o *huma.Operation, next func(*huma.Operation)) {
// Attempt to skip validation, group-wide.
o.SkipValidateBody = true
o.SkipValidateParams = true
next(o)
// Attempt to skip validation, group-wide, again.
o.SkipValidateBody = true
o.SkipValidateParams = true
})
type Request struct {
Body struct {
Name string `json:"name" maxLength:"10"`
Enum Enum `json:"enum"`
}
}
huma.Register(group, huma.Operation{
Method: http.MethodPut,
Path: "/example",
}, func(ctx context.Context, input *Request) (*struct{}, error) {
return &struct{}{}, nil
})
addr := ":8182"
if err := http.ListenAndServe(addr, mux); err != nil {
log.Fatalf("failed to start server: %v", err)
}
fmt.Printf("Server started on %s\n", addr)
}
```
**Step 2**: Send a cURL that violates the validation:
```bash
curl --request PUT \
--url http://localhost:8182/group/example \
--header 'Accept: application/problem+json' \
--header 'Content-Type: application/json' \
--data '{
"enum": "not-a-valid-enum",
"name": "very very very large name"
}'
```
**Step 3**: Receives failure for both validations (via `SchemaTransformer` or struct tags):
```jsonc
// 422 Unprocessable Entity
{
"$schema": "http://localhost:8182/schemas/ErrorModel.json",
"title": "Unprocessable Entity",
"status": 422,
"detail": "validation failed",
"errors": [
{
"message": "expected value to be one of \"foo, bar\"",
"location": "body.enum",
"value": "not-a-valid-enum"
},
{
"message": "expected length <= 10",
"location": "body.name",
"value": "very very very large name"
}
]
}
```
Expected result should be `204 No Content`.
Adding `SkipValidateBody`/`SkipValidateParams` directly into `huma.Operation` works properly.
# Environment
Huma: `github.com/danielgtaylor/huma/v2 v2.37.3`
Go: `go version go1.25.5 darwin/arm64`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.