Skip to content

Commit 2416dfb

Browse files
fix: correct parameter binding in all server templates
Fix three categories of template bugs across all 8 server frameworks: 1. Query params (non-explode): Templates passed (bool, url.Values) to BindFormParam which expects (ParamLocation, string). Fixed by branching on .Explode — non-explode now passes ParamLocationQuery + single value. 2. Cookie params (explode): Templates passed (ParamLocation, string) to BindFormExplodeParam which expects (bool, url.Values). Fixed by always using BindFormParam for cookies since cookies are single values. 3. Deep object params: ComputeBindFunc/ComputeStyleFunc generated non-existent "DeepObjectExplode" variants. Fixed by special-casing deepObject (always requires explode=true per OpenAPI spec). Also adds _ = err to suppress unused variable when only passthrough path params exist. Closes: oapi-codegen/oapi-codegen-exp-backup#29
1 parent 6e36bfb commit 2416dfb

19 files changed

Lines changed: 196 additions & 26 deletions

File tree

codegen/internal/operation.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ type SecurityRequirement struct {
249249
// ComputeStyleFunc returns the style function name for a parameter.
250250
func ComputeStyleFunc(style string, explode bool) string {
251251
base := "Style" + ToCamelCase(style)
252-
if explode {
252+
// deepObject always requires explode=true per OpenAPI spec,
253+
// so there is no separate "Explode" variant.
254+
if explode && style != "deepObject" {
253255
return base + "ExplodeParam"
254256
}
255257
return base + "Param"
@@ -258,7 +260,9 @@ func ComputeStyleFunc(style string, explode bool) string {
258260
// ComputeBindFunc returns the bind function name for a parameter.
259261
func ComputeBindFunc(style string, explode bool) string {
260262
base := "Bind" + ToCamelCase(style)
261-
if explode {
263+
// deepObject always requires explode=true per OpenAPI spec,
264+
// so there is no separate "Explode" variant.
265+
if explode && style != "deepObject" {
262266
return base + "ExplodeParam"
263267
}
264268
return base + "Param"

codegen/internal/templates/files/server/chi/receiver.go.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,13 @@ func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterfac
5252
}{{ end }}
5353
{{- end }}
5454
{{- if .IsStyled }}
55+
{{- if eq .Style "deepObject" }}
56+
err = {{ .BindFunc }}("{{ .Name }}", r.URL.Query(), &params.{{ .GoName }})
57+
{{- else if .Explode }}
5558
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), &params.{{ .GoName }})
59+
{{- else }}
60+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, r.URL.Query().Get("{{ .Name }}"), &params.{{ .GoName }})
61+
{{- end }}
5662
if err != nil {
5763
errHandler(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err})
5864
return

codegen/internal/templates/files/server/chi/wrapper.go.tmpl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type MiddlewareFunc func(http.Handler) http.Handler
1919
func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r *http.Request) {
2020
{{- if or .PathParams .HasParams }}
2121
var err error
22+
_ = err
2223
{{- end }}
2324
{{ range .PathParams }}
2425
// ------------- Path parameter "{{ .Name }}" -------------
@@ -73,7 +74,13 @@ func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r
7374
}{{ end }}
7475
{{- end }}
7576
{{- if .IsStyled }}
77+
{{- if eq .Style "deepObject" }}
78+
err = {{ .BindFunc }}("{{ .Name }}", r.URL.Query(), &params.{{ .GoName }})
79+
{{- else if .Explode }}
7680
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, r.URL.Query(), &params.{{ .GoName }})
81+
{{- else }}
82+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, r.URL.Query().Get("{{ .Name }}"), &params.{{ .GoName }})
83+
{{- end }}
7784
if err != nil {
7885
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err})
7986
return
@@ -139,7 +146,7 @@ func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(w http.ResponseWriter, r
139146
{{- end }}
140147
{{- if .IsStyled }}
141148
var value {{ .TypeDecl }}
142-
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
149+
err = {{ runtimeParamsPrefix }}BindFormParam("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
143150
if err != nil {
144151
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{ .Name }}", Err: err})
145152
return

codegen/internal/templates/files/server/echo-v4/receiver.go.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterfac
4141
}{{ end }}
4242
{{- end }}
4343
{{- if .IsStyled }}
44+
{{- if eq .Style "deepObject" }}
45+
err = {{ .BindFunc }}("{{ .Name }}", ctx.QueryParams(), &params.{{ .GoName }})
46+
{{- else if .Explode }}
4447
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), &params.{{ .GoName }})
48+
{{- else }}
49+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, ctx.QueryParam("{{ .Name }}"), &params.{{ .GoName }})
50+
{{- end }}
4551
if err != nil {
4652
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
4753
}

codegen/internal/templates/files/server/echo-v4/wrapper.go.tmpl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx echo.Context) error {
4444
{{ range .QueryParams }}
4545
// ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" -------------
4646
{{- if .IsStyled }}
47+
{{- if eq .Style "deepObject" }}
48+
err = {{ .BindFunc }}("{{ .Name }}", ctx.QueryParams(), &params.{{ .GoName }})
49+
{{- else if .Explode }}
4750
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), &params.{{ .GoName }})
51+
{{- else }}
52+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, ctx.QueryParam("{{ .Name }}"), &params.{{ .GoName }})
53+
{{- end }}
4854
if err != nil {
4955
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
5056
}
@@ -116,7 +122,7 @@ func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx echo.Context) error {
116122
{{- end }}
117123
{{- if .IsStyled }}
118124
var value {{ .TypeDecl }}
119-
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
125+
err = {{ runtimeParamsPrefix }}BindFormParam("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
120126
if err != nil {
121127
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
122128
}

codegen/internal/templates/files/server/echo/receiver.go.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterfac
4141
}{{ end }}
4242
{{- end }}
4343
{{- if .IsStyled }}
44+
{{- if eq .Style "deepObject" }}
45+
err = {{ .BindFunc }}("{{ .Name }}", ctx.QueryParams(), &params.{{ .GoName }})
46+
{{- else if .Explode }}
4447
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), &params.{{ .GoName }})
48+
{{- else }}
49+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, ctx.QueryParam("{{ .Name }}"), &params.{{ .GoName }})
50+
{{- end }}
4551
if err != nil {
4652
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
4753
}

codegen/internal/templates/files/server/echo/wrapper.go.tmpl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,13 @@ func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx *echo.Context) error {
4444
{{ range .QueryParams }}
4545
// ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" -------------
4646
{{- if .IsStyled }}
47+
{{- if eq .Style "deepObject" }}
48+
err = {{ .BindFunc }}("{{ .Name }}", ctx.QueryParams(), &params.{{ .GoName }})
49+
{{- else if .Explode }}
4750
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, ctx.QueryParams(), &params.{{ .GoName }})
51+
{{- else }}
52+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, ctx.QueryParam("{{ .Name }}"), &params.{{ .GoName }})
53+
{{- end }}
4854
if err != nil {
4955
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
5056
}
@@ -116,7 +122,7 @@ func (w *ServerInterfaceWrapper) {{ .GoOperationID }}(ctx *echo.Context) error {
116122
{{- end }}
117123
{{- if .IsStyled }}
118124
var value {{ .TypeDecl }}
119-
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
125+
err = {{ runtimeParamsPrefix }}BindFormParam("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie.Value, &value)
120126
if err != nil {
121127
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
122128
}

codegen/internal/templates/files/server/fiber/receiver.go.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterfac
4141
}{{ end }}
4242
{{- end }}
4343
{{- if .IsStyled }}
44+
{{- if eq .Style "deepObject" }}
45+
err = {{ .BindFunc }}("{{ .Name }}", c.Queries(), &params.{{ .GoName }})
46+
{{- else if .Explode }}
4447
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Queries(), &params.{{ .GoName }})
48+
{{- else }}
49+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, c.Query("{{ .Name }}"), &params.{{ .GoName }})
50+
{{- end }}
4551
if err != nil {
4652
return fiber.NewError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
4753
}

codegen/internal/templates/files/server/fiber/wrapper.go.tmpl

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type ServerInterfaceWrapper struct {
1414
func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c fiber.Ctx) error {
1515
{{- if or .PathParams .HasParams }}
1616
var err error
17+
_ = err
1718
{{- end }}
1819
{{ range .PathParams }}
1920
// ------------- Path parameter "{{ .Name }}" -------------
@@ -52,7 +53,13 @@ func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c fiber.Ctx) error {
5253
{{ range .QueryParams }}
5354
// ------------- {{ if .Required }}Required{{ else }}Optional{{ end }} query parameter "{{ .Name }}" -------------
5455
{{- if .IsStyled }}
56+
{{- if eq .Style "deepObject" }}
57+
err = {{ .BindFunc }}("{{ .Name }}", query, &params.{{ .GoName }})
58+
{{- else if .Explode }}
5559
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, query, &params.{{ .GoName }})
60+
{{- else }}
61+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, query.Get("{{ .Name }}"), &params.{{ .GoName }})
62+
{{- end }}
5663
if err != nil {
5764
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
5865
}
@@ -121,7 +128,7 @@ func (siw *ServerInterfaceWrapper) {{ .GoOperationID }}(c fiber.Ctx) error {
121128
{{- end }}
122129
{{- if .IsStyled }}
123130
var value {{ .TypeDecl }}
124-
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie, &value)
131+
err = {{ runtimeParamsPrefix }}BindFormParam("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationCookie, cookie, &value)
125132
if err != nil {
126133
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err))
127134
}

codegen/internal/templates/files/server/gin/receiver.go.tmpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ func {{ .GoOperationID }}{{ $.Prefix }}Handler(si {{ $.Prefix }}ReceiverInterfac
4343
}{{ end }}
4444
{{- end }}
4545
{{- if .IsStyled }}
46+
{{- if eq .Style "deepObject" }}
47+
err = {{ .BindFunc }}("{{ .Name }}", c.Request.URL.Query(), &params.{{ .GoName }})
48+
{{- else if .Explode }}
4649
err = {{ .BindFunc }}("{{ .Name }}", {{ .Required }}, c.Request.URL.Query(), &params.{{ .GoName }})
50+
{{- else }}
51+
err = {{ .BindFunc }}("{{ .Name }}", {{ runtimeParamsPrefix }}ParamLocationQuery, c.Request.URL.Query().Get("{{ .Name }}"), &params.{{ .GoName }})
52+
{{- end }}
4753
if err != nil {
4854
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("Invalid format for parameter {{ .Name }}: %s", err)})
4955
return

0 commit comments

Comments
 (0)