Skip to content

Commit

Permalink
Allow using pointers in input struct if they are not path/query/heade…
Browse files Browse the repository at this point in the history
…r/cookie parameters
  • Loading branch information
lsdch committed Aug 29, 2024
1 parent 77c7a16 commit b5c4b69
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
18 changes: 9 additions & 9 deletions huma.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,6 @@ func findParams(registry Registry, op *Operation, t reflect.Type) *findResult[*p
return nil
}

if f.Type.Kind() == reflect.Pointer {
// TODO: support pointers? The problem is that when we dynamically
// create an instance of the input struct the `params.Every(...)`
// call cannot set them as the value is `reflect.Invalid` unless
// dynamically allocated, but we don't know when to allocate until
// after the `Every` callback has run. Doable, but a bigger change.
panic("pointers are not supported for path/query/header parameters")
}

pfi := &paramFieldInfo{
Type: f.Type,
}
Expand Down Expand Up @@ -146,6 +137,15 @@ func findParams(registry Registry, op *Operation, t reflect.Type) *findResult[*p
return nil
}

if f.Type.Kind() == reflect.Pointer {
// TODO: support pointers? The problem is that when we dynamically
// create an instance of the input struct the `params.Every(...)`
// call cannot set them as the value is `reflect.Invalid` unless
// dynamically allocated, but we don't know when to allocate until
// after the `Every` callback has run. Doable, but a bigger change.
panic("pointers are not supported for path/query/header parameters")
}

pfi.Schema = SchemaFromField(registry, f, "")

var example any
Expand Down
32 changes: 32 additions & 0 deletions huma_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2059,6 +2059,38 @@ func TestResolverCompositionCalledOnce(t *testing.T) {
assert.Equal(t, http.StatusNoContent, w.Code, w.Body.String())
}

type ResolverWithPointer struct {
Ptr *string
}

func (r *ResolverWithPointer) Resolve(ctx huma.Context) []error {
r.Ptr = new(string)
*r.Ptr = "String"
return nil
}

func TestResolverWithPointer(t *testing.T) {
// Allow using pointers in input structs if they are not path/query/header/cookie parameters
r, app := humatest.New(t, huma.DefaultConfig("Test API", "1.0.0"))
huma.Register(app, huma.Operation{
OperationID: "test",
Method: http.MethodPut,
Path: "/test",
}, func(ctx context.Context, input *struct {
ResolverWithPointer
}) (*struct{}, error) {
// Exactly one call should have been made to the resolver.
assert.Equal(t, "String", *input.Ptr)
return nil, nil
})

req, _ := http.NewRequest(http.MethodPut, "/test", strings.NewReader(`{}`))
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusNoContent, w.Code, w.Body.String())
}

func TestParamPointerPanics(t *testing.T) {
// For now, we don't support these, so we panic rather than have subtle
// bugs that are hard to track down.
Expand Down

0 comments on commit b5c4b69

Please sign in to comment.