Skip to content

Commit 05453ef

Browse files
authored
openapi3filter: fix array of primitives query parameter types (#921)
* fix array of primitives query parameter types * update tests * fix parameter checks * add test cases
1 parent 7aa9f7e commit 05453ef

File tree

4 files changed

+311
-56
lines changed

4 files changed

+311
-56
lines changed

openapi3/schema.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1737,7 +1737,7 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
17371737
}
17381738
case f.regexp == nil && f.callback != nil:
17391739
if err := f.callback(value); err != nil {
1740-
var schemaErr = &SchemaError{}
1740+
schemaErr := &SchemaError{}
17411741
if errors.As(err, &schemaErr) {
17421742
formatStrErr = fmt.Sprintf(`string doesn't match the format %q (%s)`, format, schemaErr.Reason)
17431743
} else {

openapi3filter/req_resp_decoder.go

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ func findNestedSchema(parentSchema *openapi3.SchemaRef, keys []string) (*openapi
914914
// The function returns an error when an error happened while parse object's properties.
915915
func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string]interface{}, error) {
916916
obj := make(map[string]interface{})
917+
917918
for propName, propSchema := range schema.Value.Properties {
918919
switch {
919920
case propSchema.Value.Type.Is("array"):
@@ -924,7 +925,12 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
924925
return nil, handlePropParseError([]string{propName}, err)
925926
}
926927
}
927-
obj[propName] = vals
928+
929+
ivals, err := convertArrayParameterToType(vals, propSchema.Value.Items.Value.Type)
930+
if err != nil {
931+
return nil, handlePropParseError([]string{propName}, err)
932+
}
933+
obj[propName] = ivals
928934
case propSchema.Value.Type.Is("object"):
929935
for prop := range props {
930936
if !strings.HasPrefix(prop, propName+urlDecoderDelimiter) {
@@ -943,7 +949,11 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
943949
return nil, handlePropParseError(mapKeys, err)
944950
}
945951
}
946-
deepSet(obj, mapKeys, vals)
952+
ivals, err := convertArrayParameterToType(vals, nestedSchema.Value.Items.Value.Type)
953+
if err != nil {
954+
return nil, handlePropParseError(mapKeys, err)
955+
}
956+
deepSet(obj, mapKeys, ivals)
947957
continue
948958
}
949959
value, err := parsePrimitive(props[prop], nestedSchema)
@@ -960,9 +970,55 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
960970
obj[propName] = value
961971
}
962972
}
973+
963974
return obj, nil
964975
}
965976

977+
func convertArrayParameterToType(strArray []string, typ *openapi3.Types) (interface{}, error) {
978+
var iarr []interface{}
979+
switch {
980+
case typ.Permits(openapi3.TypeBoolean):
981+
for _, str := range strArray {
982+
if str == "" {
983+
continue
984+
}
985+
parsedBool, err := strconv.ParseBool(str)
986+
if err != nil {
987+
return nil, err
988+
}
989+
iarr = append(iarr, parsedBool)
990+
}
991+
case typ.Permits(openapi3.TypeInteger):
992+
for _, str := range strArray {
993+
if str == "" {
994+
continue
995+
}
996+
parsedInt, err := strconv.Atoi(str)
997+
if err != nil {
998+
return nil, err
999+
}
1000+
iarr = append(iarr, parsedInt)
1001+
}
1002+
case typ.Permits(openapi3.TypeNumber):
1003+
for _, str := range strArray {
1004+
if str == "" {
1005+
continue
1006+
}
1007+
parsedFloat, err := strconv.ParseFloat(str, 64)
1008+
if err != nil {
1009+
return nil, err
1010+
}
1011+
iarr = append(iarr, parsedFloat)
1012+
}
1013+
case typ.Permits(openapi3.TypeString):
1014+
return strArray, nil
1015+
default:
1016+
return nil, fmt.Errorf("unsupported parameter array type: %s", typ)
1017+
}
1018+
1019+
return iarr, nil
1020+
}
1021+
9661022
func handlePropParseError(path []string, err error) error {
9671023
if v, ok := err.(*ParseError); ok {
9681024
return &ParseError{path: pathFromKeys(path), Cause: v}

openapi3filter/testdata/fixtures/petstore.json

Lines changed: 116 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,98 @@
140140
}
141141
}
142142
},
143+
"/pet/filter": {
144+
"get": {
145+
"tags": [
146+
"pet"
147+
],
148+
"summary": "Finds Pets by status",
149+
"operationId": "filterPets",
150+
"parameters": [
151+
{
152+
"in": "query",
153+
"name": "deepFilter",
154+
"style": "deepObject",
155+
"explode": true,
156+
"allowReserved": true,
157+
"schema": {
158+
"type": "object",
159+
"properties": {
160+
"strings": {
161+
"type": "array",
162+
"items": {
163+
"type": "string"
164+
}
165+
},
166+
"booleans": {
167+
"type": "array",
168+
"items": {
169+
"type": "boolean"
170+
}
171+
},
172+
"numbers": {
173+
"type": "array",
174+
"items": {
175+
"type": "number"
176+
}
177+
},
178+
"integers": {
179+
"type": "array",
180+
"items": {
181+
"type": "integer"
182+
}
183+
}
184+
}
185+
}
186+
}
187+
],
188+
"responses": {
189+
"200": {
190+
"description": "successful operation",
191+
"content": {
192+
"application/xml": {
193+
"schema": {
194+
"type": "array",
195+
"items": {
196+
"allOf": [
197+
{
198+
"$ref": "#/components/schemas/Pet"
199+
},
200+
{
201+
"$ref": "#/components/schemas/PetRequiredProperties"
202+
}
203+
]
204+
}
205+
}
206+
},
207+
"application/json": {
208+
"schema": {
209+
"type": "array",
210+
"items": {
211+
"allOf": [
212+
{
213+
"$ref": "#/components/schemas/Pet"
214+
},
215+
{
216+
"$ref": "#/components/schemas/PetRequiredProperties"
217+
}
218+
]
219+
}
220+
}
221+
}
222+
}
223+
}
224+
},
225+
"security": [
226+
{
227+
"petstore_auth": [
228+
"write:pets",
229+
"read:pets"
230+
]
231+
}
232+
]
233+
}
234+
},
143235
"/pet/findByStatus": {
144236
"get": {
145237
"tags": [
@@ -178,8 +270,12 @@
178270
"type": "array",
179271
"items": {
180272
"allOf": [
181-
{"$ref": "#/components/schemas/Pet"},
182-
{"$ref": "#/components/schemas/PetRequiredProperties"}
273+
{
274+
"$ref": "#/components/schemas/Pet"
275+
},
276+
{
277+
"$ref": "#/components/schemas/PetRequiredProperties"
278+
}
183279
]
184280
}
185281
}
@@ -189,8 +285,12 @@
189285
"type": "array",
190286
"items": {
191287
"allOf": [
192-
{"$ref": "#/components/schemas/Pet"},
193-
{"$ref": "#/components/schemas/PetRequiredProperties"}
288+
{
289+
"$ref": "#/components/schemas/Pet"
290+
},
291+
{
292+
"$ref": "#/components/schemas/PetRequiredProperties"
293+
}
194294
]
195295
}
196296
}
@@ -283,8 +383,12 @@
283383
"type": "array",
284384
"items": {
285385
"allOf": [
286-
{"$ref": "#/components/schemas/Pet"},
287-
{"$ref": "#/components/schemas/PetRequiredProperties"}
386+
{
387+
"$ref": "#/components/schemas/Pet"
388+
},
389+
{
390+
"$ref": "#/components/schemas/PetRequiredProperties"
391+
}
288392
]
289393
}
290394
}
@@ -294,8 +398,12 @@
294398
"type": "array",
295399
"items": {
296400
"allOf": [
297-
{"$ref": "#/components/schemas/Pet"},
298-
{"$ref": "#/components/schemas/PetRequiredProperties"}
401+
{
402+
"$ref": "#/components/schemas/Pet"
403+
},
404+
{
405+
"$ref": "#/components/schemas/PetRequiredProperties"
406+
}
299407
]
300408
}
301409
}

0 commit comments

Comments
 (0)