Skip to content

Commit 51d13f4

Browse files
refactor: wire codegen and templates to ParameterOptions API
Complete the runtime consolidation by updating all code generation: - ComputeBindFunc(style, location) picks single-value vs query entry point based on parameter location - ComputeStyleFunc(style) no longer takes explode arg - Add SchemaType()/SchemaFormat() methods to ParameterDescriptor - All 16 server templates construct ParameterOptions inline with ParamLocation, Explode, Required, Type, Format — zero branching - Client template (request_builders.go.tmpl) updated for StyleFunc - Runtime unit tests updated for new signatures Templates now follow the V2 pattern: the struct literal is built directly in the template using fields from the parameter descriptor.
1 parent 9b3aabc commit 51d13f4

48 files changed

Lines changed: 4085 additions & 5705 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

codegen/internal/gather_operations.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ func (g *operationGatherer) gatherParameter(param *v3.Parameter) (*ParameterDesc
231231
required = *param.Required
232232
}
233233

234-
styleFunc := ComputeStyleFunc(style, explode)
235-
bindFunc := ComputeBindFunc(style, explode)
234+
styleFunc := ComputeStyleFunc(style)
235+
bindFunc := ComputeBindFunc(style, param.In)
236236

237237
// When a runtime package is configured, prefix function names so generated
238238
// code references them from the runtime package (e.g., "params.StyleSimpleParam").

codegen/internal/operation.go

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,30 @@ func (p *ParameterDescriptor) HasOptionalPointer() bool {
171171
return true
172172
}
173173

174+
// SchemaType returns the first OpenAPI type string for this parameter's schema
175+
// (e.g., "string", "integer", "array", "object"), or empty string if unavailable.
176+
func (p *ParameterDescriptor) SchemaType() string {
177+
if p.Spec != nil && p.Spec.Schema != nil {
178+
if schema := p.Spec.Schema.Schema(); schema != nil {
179+
if len(schema.Type) > 0 {
180+
return schema.Type[0]
181+
}
182+
}
183+
}
184+
return ""
185+
}
186+
187+
// SchemaFormat returns the OpenAPI format string for this parameter's schema
188+
// (e.g., "int32", "date-time"), or empty string if unavailable.
189+
func (p *ParameterDescriptor) SchemaFormat() string {
190+
if p.Spec != nil && p.Spec.Schema != nil {
191+
if schema := p.Spec.Schema.Schema(); schema != nil {
192+
return schema.Format
193+
}
194+
}
195+
return ""
196+
}
197+
174198
// RequestBodyDescriptor describes a request body for a specific content type.
175199
type RequestBodyDescriptor struct {
176200
ContentType string // "application/json", "multipart/form-data", etc.
@@ -247,23 +271,16 @@ type SecurityRequirement struct {
247271
// Helper functions for computing descriptor fields
248272

249273
// ComputeStyleFunc returns the style function name for a parameter.
250-
func ComputeStyleFunc(style string, explode bool) string {
251-
base := "Style" + ToCamelCase(style)
252-
// deepObject always requires explode=true per OpenAPI spec,
253-
// so there is no separate "Explode" variant.
254-
if explode && style != "deepObject" {
255-
return base + "ExplodeParam"
256-
}
257-
return base + "Param"
274+
func ComputeStyleFunc(style string) string {
275+
return "Style" + ToCamelCase(style) + "Param"
258276
}
259277

260278
// ComputeBindFunc returns the bind function name for a parameter.
261-
func ComputeBindFunc(style string, explode bool) string {
279+
// Query parameters use a separate entry point that takes url.Values.
280+
func ComputeBindFunc(style string, location string) string {
262281
base := "Bind" + ToCamelCase(style)
263-
// deepObject always requires explode=true per OpenAPI spec,
264-
// so there is no separate "Explode" variant.
265-
if explode && style != "deepObject" {
266-
return base + "ExplodeParam"
282+
if location == "query" {
283+
return base + "QueryParam"
267284
}
268285
return base + "Param"
269286
}

codegen/internal/runtime/params/style_deep_object_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func TestStyleDeepObjectParam_Struct(t *testing.T) {
1313
Color string `json:"color"`
1414
Size int `json:"size"`
1515
}
16-
result, err := StyleDeepObjectParam("filter", ParamLocationQuery, obj{Color: "red", Size: 10})
16+
result, err := StyleDeepObjectParam("filter", obj{Color: "red", Size: 10}, ParameterOptions{ParamLocation: ParamLocationQuery})
1717
require.NoError(t, err)
1818
assert.Equal(t, "filter[color]=red&filter[size]=10", result)
1919
}
@@ -26,10 +26,10 @@ func TestStyleDeepObjectParam_NestedStruct(t *testing.T) {
2626
Name string `json:"name"`
2727
Address inner `json:"address"`
2828
}
29-
result, err := StyleDeepObjectParam("user", ParamLocationQuery, outer{
29+
result, err := StyleDeepObjectParam("user", outer{
3030
Name: "alice",
3131
Address: inner{City: "NYC"},
32-
})
32+
}, ParameterOptions{ParamLocation: ParamLocationQuery})
3333
require.NoError(t, err)
3434
assert.Equal(t, "user[address][city]=NYC&user[name]=alice", result)
3535
}
@@ -40,15 +40,15 @@ func TestStyleDeepObjectParam_Roundtrip_Struct(t *testing.T) {
4040
Size int `json:"size"`
4141
}
4242
original := obj{Color: "blue", Size: 42}
43-
styled, err := StyleDeepObjectParam("filter", ParamLocationQuery, original)
43+
styled, err := StyleDeepObjectParam("filter", original, ParameterOptions{ParamLocation: ParamLocationQuery})
4444
require.NoError(t, err)
4545

4646
// Parse to url.Values
4747
vals, err := url.ParseQuery(styled)
4848
require.NoError(t, err)
4949

5050
var result obj
51-
err = BindDeepObjectParam("filter", vals, &result)
51+
err = BindDeepObjectQueryParam("filter", vals, &result, ParameterOptions{})
5252
require.NoError(t, err)
5353
assert.Equal(t, original, result)
5454
}
@@ -65,15 +65,15 @@ func TestStyleDeepObjectParam_Roundtrip_NestedStruct(t *testing.T) {
6565
Name: "alice",
6666
Address: inner{City: "NYC"},
6767
}
68-
styled, err := StyleDeepObjectParam("user", ParamLocationQuery, original)
68+
styled, err := StyleDeepObjectParam("user", original, ParameterOptions{ParamLocation: ParamLocationQuery})
6969
require.NoError(t, err)
7070

7171
// Parse to url.Values
7272
vals, err := url.ParseQuery(styled)
7373
require.NoError(t, err)
7474

7575
var result outer
76-
err = BindDeepObjectParam("user", vals, &result)
76+
err = BindDeepObjectQueryParam("user", vals, &result, ParameterOptions{})
7777
require.NoError(t, err)
7878
assert.Equal(t, original, result)
7979
}
@@ -82,7 +82,7 @@ func TestStyleDeepObjectParam_WithSlice(t *testing.T) {
8282
type obj struct {
8383
Tags []string `json:"tags"`
8484
}
85-
result, err := StyleDeepObjectParam("filter", ParamLocationQuery, obj{Tags: []string{"a", "b"}})
85+
result, err := StyleDeepObjectParam("filter", obj{Tags: []string{"a", "b"}}, ParameterOptions{ParamLocation: ParamLocationQuery})
8686
require.NoError(t, err)
8787
assert.Equal(t, "filter[tags][0]=a&filter[tags][1]=b", result)
8888
}
@@ -92,14 +92,14 @@ func TestStyleDeepObjectParam_Roundtrip_WithSlice(t *testing.T) {
9292
Tags []string `json:"tags"`
9393
}
9494
original := obj{Tags: []string{"a", "b"}}
95-
styled, err := StyleDeepObjectParam("filter", ParamLocationQuery, original)
95+
styled, err := StyleDeepObjectParam("filter", original, ParameterOptions{ParamLocation: ParamLocationQuery})
9696
require.NoError(t, err)
9797

9898
vals, err := url.ParseQuery(styled)
9999
require.NoError(t, err)
100100

101101
var result obj
102-
err = BindDeepObjectParam("filter", vals, &result)
102+
err = BindDeepObjectQueryParam("filter", vals, &result, ParameterOptions{})
103103
require.NoError(t, err)
104104
assert.Equal(t, original, result)
105105
}

codegen/internal/runtime/params/style_form_explode_test.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ import (
99
)
1010

1111
func TestStyleFormExplodeParam_Primitive(t *testing.T) {
12-
result, err := StyleFormExplodeParam("color", ParamLocationQuery, "blue")
12+
result, err := StyleFormParam("color", "blue", ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
1313
require.NoError(t, err)
1414
assert.Equal(t, "color=blue", result)
1515
}
1616

1717
func TestStyleFormExplodeParam_Int(t *testing.T) {
18-
result, err := StyleFormExplodeParam("count", ParamLocationQuery, 5)
18+
result, err := StyleFormParam("count", 5, ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
1919
require.NoError(t, err)
2020
assert.Equal(t, "count=5", result)
2121
}
2222

2323
func TestStyleFormExplodeParam_StringSlice(t *testing.T) {
24-
result, err := StyleFormExplodeParam("tags", ParamLocationQuery, []string{"a", "b", "c"})
24+
result, err := StyleFormParam("tags", []string{"a", "b", "c"}, ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
2525
require.NoError(t, err)
2626
assert.Equal(t, "tags=a&tags=b&tags=c", result)
2727
}
@@ -31,36 +31,36 @@ func TestStyleFormExplodeParam_Struct(t *testing.T) {
3131
Color string `json:"color"`
3232
Size int `json:"size"`
3333
}
34-
result, err := StyleFormExplodeParam("filter", ParamLocationQuery, obj{Color: "red", Size: 10})
34+
result, err := StyleFormParam("filter", obj{Color: "red", Size: 10}, ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
3535
require.NoError(t, err)
3636
assert.Equal(t, "color=red&size=10", result)
3737
}
3838

3939
func TestStyleFormExplodeParam_Roundtrip_Primitive(t *testing.T) {
40-
styled, err := StyleFormExplodeParam("color", ParamLocationQuery, "blue")
40+
styled, err := StyleFormParam("color", "blue", ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
4141
require.NoError(t, err)
4242

4343
// Parse to url.Values
4444
vals, err := url.ParseQuery(styled)
4545
require.NoError(t, err)
4646

4747
var result string
48-
err = BindFormExplodeParam("color", true, vals, &result)
48+
err = BindFormQueryParam("color", vals, &result, ParameterOptions{Explode: true, Required: true})
4949
require.NoError(t, err)
5050
assert.Equal(t, "blue", result)
5151
}
5252

5353
func TestStyleFormExplodeParam_Roundtrip_StringSlice(t *testing.T) {
5454
original := []string{"a", "b", "c"}
55-
styled, err := StyleFormExplodeParam("items", ParamLocationQuery, original)
55+
styled, err := StyleFormParam("items", original, ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
5656
require.NoError(t, err)
5757

5858
// Parse to url.Values
5959
vals, err := url.ParseQuery(styled)
6060
require.NoError(t, err)
6161

6262
var result []string
63-
err = BindFormExplodeParam("items", true, vals, &result)
63+
err = BindFormQueryParam("items", vals, &result, ParameterOptions{Explode: true, Required: true})
6464
require.NoError(t, err)
6565
assert.Equal(t, original, result)
6666
}
@@ -71,15 +71,15 @@ func TestStyleFormExplodeParam_Roundtrip_Struct(t *testing.T) {
7171
Size string `json:"size"`
7272
}
7373
original := obj{Color: "blue", Size: "large"}
74-
styled, err := StyleFormExplodeParam("filter", ParamLocationQuery, original)
74+
styled, err := StyleFormParam("filter", original, ParameterOptions{ParamLocation: ParamLocationQuery, Explode: true})
7575
require.NoError(t, err)
7676

7777
// Parse to url.Values
7878
vals, err := url.ParseQuery(styled)
7979
require.NoError(t, err)
8080

8181
var result obj
82-
err = BindFormExplodeParam("filter", true, vals, &result)
82+
err = BindFormQueryParam("filter", vals, &result, ParameterOptions{Explode: true, Required: true})
8383
require.NoError(t, err)
8484
assert.Equal(t, original, result)
8585
}
@@ -88,7 +88,7 @@ func TestBindFormExplodeParam_OptionalMissing(t *testing.T) {
8888
vals := url.Values{}
8989

9090
var result *string
91-
err := BindFormExplodeParam("missing", false, vals, &result)
91+
err := BindFormQueryParam("missing", vals, &result, ParameterOptions{Explode: true})
9292
require.NoError(t, err)
9393
assert.Nil(t, result)
9494
}
@@ -97,7 +97,7 @@ func TestBindFormExplodeParam_RequiredMissing(t *testing.T) {
9797
vals := url.Values{}
9898

9999
var result string
100-
err := BindFormExplodeParam("required", true, vals, &result)
100+
err := BindFormQueryParam("required", vals, &result, ParameterOptions{Explode: true, Required: true})
101101
assert.Error(t, err)
102102
assert.Contains(t, err.Error(), "required")
103103
}

codegen/internal/runtime/params/style_form_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ import (
88
)
99

1010
func TestStyleFormParam_Primitive(t *testing.T) {
11-
result, err := StyleFormParam("color", ParamLocationQuery, "blue")
11+
result, err := StyleFormParam("color", "blue", ParameterOptions{ParamLocation: ParamLocationQuery})
1212
require.NoError(t, err)
1313
assert.Equal(t, "color=blue", result)
1414
}
1515

1616
func TestStyleFormParam_Int(t *testing.T) {
17-
result, err := StyleFormParam("count", ParamLocationQuery, 5)
17+
result, err := StyleFormParam("count", 5, ParameterOptions{ParamLocation: ParamLocationQuery})
1818
require.NoError(t, err)
1919
assert.Equal(t, "count=5", result)
2020
}
2121

2222
func TestStyleFormParam_StringSlice(t *testing.T) {
23-
result, err := StyleFormParam("tags", ParamLocationQuery, []string{"a", "b", "c"})
23+
result, err := StyleFormParam("tags", []string{"a", "b", "c"}, ParameterOptions{ParamLocation: ParamLocationQuery})
2424
require.NoError(t, err)
2525
assert.Equal(t, "tags=a,b,c", result)
2626
}
@@ -30,33 +30,33 @@ func TestStyleFormParam_Struct(t *testing.T) {
3030
Color string `json:"color"`
3131
Size int `json:"size"`
3232
}
33-
result, err := StyleFormParam("filter", ParamLocationQuery, obj{Color: "red", Size: 10})
33+
result, err := StyleFormParam("filter", obj{Color: "red", Size: 10}, ParameterOptions{ParamLocation: ParamLocationQuery})
3434
require.NoError(t, err)
3535
assert.Equal(t, "filter=color,red,size,10", result)
3636
}
3737

3838
func TestStyleFormParam_Roundtrip_Primitive(t *testing.T) {
39-
styled, err := StyleFormParam("color", ParamLocationQuery, "blue")
39+
styled, err := StyleFormParam("color", "blue", ParameterOptions{ParamLocation: ParamLocationQuery})
4040
require.NoError(t, err)
4141
// Form style: "color=blue" — the value part is "blue"
4242
assert.Equal(t, "color=blue", styled)
4343

4444
// BindFormParam takes just the value (after splitting on =)
4545
var result string
46-
err = BindFormParam("color", ParamLocationQuery, "blue", &result)
46+
err = BindFormParam("color", "blue", &result, ParameterOptions{ParamLocation: ParamLocationQuery})
4747
require.NoError(t, err)
4848
assert.Equal(t, "blue", result)
4949
}
5050

5151
func TestStyleFormParam_Roundtrip_StringSlice(t *testing.T) {
5252
original := []string{"x", "y", "z"}
53-
styled, err := StyleFormParam("items", ParamLocationQuery, original)
53+
styled, err := StyleFormParam("items", original, ParameterOptions{ParamLocation: ParamLocationQuery})
5454
require.NoError(t, err)
5555
assert.Equal(t, "items=x,y,z", styled)
5656

5757
// BindFormParam takes the value part
5858
var result []string
59-
err = BindFormParam("items", ParamLocationQuery, "x,y,z", &result)
59+
err = BindFormParam("items", "x,y,z", &result, ParameterOptions{ParamLocation: ParamLocationQuery})
6060
require.NoError(t, err)
6161
assert.Equal(t, original, result)
6262
}
@@ -67,13 +67,13 @@ func TestStyleFormParam_Roundtrip_Struct(t *testing.T) {
6767
Size string `json:"size"`
6868
}
6969
original := obj{Color: "blue", Size: "large"}
70-
styled, err := StyleFormParam("filter", ParamLocationQuery, original)
70+
styled, err := StyleFormParam("filter", original, ParameterOptions{ParamLocation: ParamLocationQuery})
7171
require.NoError(t, err)
7272
assert.Equal(t, "filter=color,blue,size,large", styled)
7373

7474
// BindFormParam takes the value part
7575
var result obj
76-
err = BindFormParam("filter", ParamLocationQuery, "color,blue,size,large", &result)
76+
err = BindFormParam("filter", "color,blue,size,large", &result, ParameterOptions{ParamLocation: ParamLocationQuery})
7777
require.NoError(t, err)
7878
assert.Equal(t, original, result)
7979
}

0 commit comments

Comments
 (0)