FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix: support x-oapi-codegen-extra-tags on path params in strict-serve… · oapi-codegen/oapi-codegen@a10a2a2 · GitHub

Commit a10a2a2

Browse files
andcommitted
fix: support x-oapi-codegen-extra-tags on path params in strict-server RequestObject
ParameterDefinition.JsonTag() only produced a `json:"..."` tag and ignored x-oapi-codegen-extra-tags. This meant path parameters in strict-server RequestObject structs never included extra struct tags, even though query/header/cookie parameters did (via GenerateParamsTypes). Update JsonTag() to read x-oapi-codegen-extra-tags from both the parameter and schema levels, with parameter-level taking precedence, matching the existing merge behavior in GenerateParamsTypes(). Fixes #2261 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f0626c2 commit a10a2a2

2 files changed

Lines changed: 116 additions & 2 deletions

File tree

‎pkg/codegen/operations.go‎

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,44 @@ func (pd ParameterDefinition) ZeroValueIsNil() bool {
6666
// JsonTag generates the JSON annotation to map GoType to json type name. If Parameter
6767
// Foo is marshaled to json as "foo", this will create the annotation
6868
// 'json:"foo"'
69+
// It also includes any additional struct tags from x-oapi-codegen-extra-tags
70+
// at the parameter or schema level (parameter-level takes precedence).
6971
func (pd *ParameterDefinition) JsonTag() string {
72+
fieldTags := make(map[string]string)
73+
7074
if pd.Required {
71-
return fmt.Sprintf("`json:\"%s\"`", pd.ParamName)
75+
fieldTags["json"] = pd.ParamName
7276
} else {
73-
return fmt.Sprintf("`json:\"%s,omitempty\"`", pd.ParamName)
77+
fieldTags["json"] = pd.ParamName + ",omitempty"
78+
}
79+
80+
// Merge x-oapi-codegen-extra-tags from schema level first, then parameter level
81+
// so that parameter-level takes precedence.
82+
if pd.Spec != nil && pd.Spec.Schema != nil && pd.Spec.Schema.Value != nil {
83+
if extension, ok := pd.Spec.Schema.Value.Extensions[extPropExtraTags]; ok {
84+
if tags, err := extExtraTags(extension); err == nil {
85+
for k, v := range tags {
86+
fieldTags[k] = v
87+
}
88+
}
89+
}
90+
}
91+
if pd.Spec != nil {
92+
if extension, ok := pd.Spec.Extensions[extPropExtraTags]; ok {
93+
if tags, err := extExtraTags(extension); err == nil {
94+
for k, v := range tags {
95+
fieldTags[k] = v
96+
}
97+
}
98+
}
99+
}
100+
101+
keys := SortedMapKeys(fieldTags)
102+
tags := make([]string, len(keys))
103+
for i, k := range keys {
104+
tags[i] = fmt.Sprintf(`%s:"%s"`, k, fieldTags[k])
74105
}
106+
return "`" + strings.Join(tags, " ") + "`"
75107
}
76108

77109
func (pd *ParameterDefinition) IsJson() bool {

‎pkg/codegen/operations_test.go‎

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"testing"
1919

2020
"github.com/getkin/kin-openapi/openapi3"
21+
"github.com/stretchr/testify/assert"
2122
)
2223

2324
func TestIsJson(t *testing.T) {
@@ -146,3 +147,84 @@ func TestGenerateDefaultOperationID(t *testing.T) {
146147
}
147148
}
148149
}
150+
151+
func TestJsonTag(t *testing.T) {
152+
t.Run("required param with no extra tags", func(t *testing.T) {
153+
pd := ParameterDefinition{
154+
ParamName: "foo",
155+
Required: true,
156+
Spec: &openapi3.Parameter{},
157+
}
158+
assert.Equal(t, "`json:\"foo\"`", pd.JsonTag())
159+
})
160+
161+
t.Run("optional param with no extra tags", func(t *testing.T) {
162+
pd := ParameterDefinition{
163+
ParamName: "foo",
164+
Required: false,
165+
Spec: &openapi3.Parameter{},
166+
}
167+
assert.Equal(t, "`json:\"foo,omitempty\"`", pd.JsonTag())
168+
})
169+
170+
t.Run("extra tags at parameter level", func(t *testing.T) {
171+
pd := ParameterDefinition{
172+
ParamName: "foo",
173+
Required: true,
174+
Spec: &openapi3.Parameter{
175+
Extensions: map[string]any{
176+
"x-oapi-codegen-extra-tags": map[string]any{
177+
"validate": "required",
178+
"db": "foo_col",
179+
},
180+
},
181+
},
182+
}
183+
assert.Equal(t, "`db:\"foo_col\" json:\"foo\" validate:\"required\"`", pd.JsonTag())
184+
})
185+
186+
t.Run("extra tags at schema level", func(t *testing.T) {
187+
pd := ParameterDefinition{
188+
ParamName: "foo",
189+
Required: true,
190+
Spec: &openapi3.Parameter{
191+
Schema: &openapi3.SchemaRef{
192+
Value: &openapi3.Schema{
193+
Extensions: map[string]any{
194+
"x-oapi-codegen-extra-tags": map[string]any{
195+
"validate": "required",
196+
},
197+
},
198+
},
199+
},
200+
},
201+
}
202+
assert.Equal(t, "`json:\"foo\" validate:\"required\"`", pd.JsonTag())
203+
})
204+
205+
t.Run("parameter level takes precedence over schema level", func(t *testing.T) {
206+
pd := ParameterDefinition{
207+
ParamName: "foo",
208+
Required: true,
209+
Spec: &openapi3.Parameter{
210+
Extensions: map[string]any{
211+
"x-oapi-codegen-extra-tags": map[string]any{
212+
"validate": "param-level",
213+
},
214+
},
215+
Schema: &openapi3.SchemaRef{
216+
Value: &openapi3.Schema{
217+
Extensions: map[string]any{
218+
"x-oapi-codegen-extra-tags": map[string]any{
219+
"validate": "schema-level",
220+
"db": "foo_col",
221+
},
222+
},
223+
},
224+
},
225+
},
226+
}
227+
// Parameter-level "validate" wins, schema-level "db" is kept
228+
assert.Equal(t, "`db:\"foo_col\" json:\"foo\" validate:\"param-level\"`", pd.JsonTag())
229+
})
230+
}

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL