diff --git a/binding/form_mapping.go b/binding/form_mapping.go index 45a39e15..35a8df64 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -35,6 +35,23 @@ func mapForm(ptr any, form map[string][]string) error { return mapFormByTag(ptr, form, "form") } +func mapQuery(ptr any, form map[string][]string) error { + // Try binding with "query" tags first (logical behavior) + err := mapFormByTag(ptr, form, "query") + if err != nil { + return err + } + + // For backward compatibility, also try "form" tags + // This allows mixed usage and maintains compatibility + err = mapFormByTag(ptr, form, "form") + if err != nil { + return err + } + + return nil +} + func MapFormWithTag(ptr any, form map[string][]string, tag string) error { return mapFormByTag(ptr, form, tag) } diff --git a/binding/query.go b/binding/query.go index c958b88b..72613953 100644 --- a/binding/query.go +++ b/binding/query.go @@ -14,7 +14,7 @@ func (queryBinding) Name() string { func (queryBinding) Bind(req *http.Request, obj any) error { values := req.URL.Query() - if err := mapForm(obj, values); err != nil { + if err := mapQuery(obj, values); err != nil { return err } return validate(obj) diff --git a/binding/query_test.go b/binding/query_test.go new file mode 100644 index 00000000..a8d30c95 --- /dev/null +++ b/binding/query_test.go @@ -0,0 +1,55 @@ +package binding + +import ( + "net/http" + "net/url" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestQueryBindingWithQueryTag(t *testing.T) { + var s struct { + Foo string `query:"foo"` + Bar string `query:"bar"` + } + + request := &http.Request{URL: &url.URL{RawQuery: "foo=HELLO&bar=WORLD"}} + + err := queryBinding{}.Bind(request, &s) + require.NoError(t, err) + + assert.Equal(t, "HELLO", s.Foo) + assert.Equal(t, "WORLD", s.Bar) +} + +func TestQueryBindingWithFormTag(t *testing.T) { + var s struct { + Foo string `form:"foo"` + Bar string `form:"bar"` + } + + request := &http.Request{URL: &url.URL{RawQuery: "foo=HELLO&bar=WORLD"}} + + err := queryBinding{}.Bind(request, &s) + require.NoError(t, err) + + assert.Equal(t, "HELLO", s.Foo) + assert.Equal(t, "WORLD", s.Bar) +} + +func TestQueryBindingMixedTags(t *testing.T) { + var s struct { + Foo string `query:"foo"` + Bar string `form:"bar"` + } + + request := &http.Request{URL: &url.URL{RawQuery: "foo=HELLO&bar=WORLD"}} + + err := queryBinding{}.Bind(request, &s) + require.NoError(t, err) + + assert.Equal(t, "HELLO", s.Foo) + assert.Equal(t, "WORLD", s.Bar) +} \ No newline at end of file