Skip to content

Commit

Permalink
openapi3filter: fix array of primitives query parameter types (#921)
Browse files Browse the repository at this point in the history
* fix array of primitives query parameter types

* update tests

* fix parameter checks

* add test cases
  • Loading branch information
danicc097 committed Mar 9, 2024
1 parent 7aa9f7e commit 05453ef
Show file tree
Hide file tree
Showing 4 changed files with 311 additions and 56 deletions.
2 changes: 1 addition & 1 deletion openapi3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -1737,7 +1737,7 @@ func (schema *Schema) visitJSONString(settings *schemaValidationSettings, value
}
case f.regexp == nil && f.callback != nil:
if err := f.callback(value); err != nil {
var schemaErr = &SchemaError{}
schemaErr := &SchemaError{}
if errors.As(err, &schemaErr) {
formatStrErr = fmt.Sprintf(`string doesn't match the format %q (%s)`, format, schemaErr.Reason)
} else {
Expand Down
60 changes: 58 additions & 2 deletions openapi3filter/req_resp_decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ func findNestedSchema(parentSchema *openapi3.SchemaRef, keys []string) (*openapi
// The function returns an error when an error happened while parse object's properties.
func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string]interface{}, error) {
obj := make(map[string]interface{})

for propName, propSchema := range schema.Value.Properties {
switch {
case propSchema.Value.Type.Is("array"):
Expand All @@ -924,7 +925,12 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
return nil, handlePropParseError([]string{propName}, err)
}
}
obj[propName] = vals

ivals, err := convertArrayParameterToType(vals, propSchema.Value.Items.Value.Type)
if err != nil {
return nil, handlePropParseError([]string{propName}, err)
}
obj[propName] = ivals
case propSchema.Value.Type.Is("object"):
for prop := range props {
if !strings.HasPrefix(prop, propName+urlDecoderDelimiter) {
Expand All @@ -943,7 +949,11 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
return nil, handlePropParseError(mapKeys, err)
}
}
deepSet(obj, mapKeys, vals)
ivals, err := convertArrayParameterToType(vals, nestedSchema.Value.Items.Value.Type)
if err != nil {
return nil, handlePropParseError(mapKeys, err)
}
deepSet(obj, mapKeys, ivals)
continue
}
value, err := parsePrimitive(props[prop], nestedSchema)
Expand All @@ -960,9 +970,55 @@ func makeObject(props map[string]string, schema *openapi3.SchemaRef) (map[string
obj[propName] = value
}
}

return obj, nil
}

func convertArrayParameterToType(strArray []string, typ *openapi3.Types) (interface{}, error) {
var iarr []interface{}
switch {
case typ.Permits(openapi3.TypeBoolean):
for _, str := range strArray {
if str == "" {
continue
}
parsedBool, err := strconv.ParseBool(str)
if err != nil {
return nil, err
}
iarr = append(iarr, parsedBool)
}
case typ.Permits(openapi3.TypeInteger):
for _, str := range strArray {
if str == "" {
continue
}
parsedInt, err := strconv.Atoi(str)
if err != nil {
return nil, err
}
iarr = append(iarr, parsedInt)
}
case typ.Permits(openapi3.TypeNumber):
for _, str := range strArray {
if str == "" {
continue
}
parsedFloat, err := strconv.ParseFloat(str, 64)
if err != nil {
return nil, err
}
iarr = append(iarr, parsedFloat)
}
case typ.Permits(openapi3.TypeString):
return strArray, nil
default:
return nil, fmt.Errorf("unsupported parameter array type: %s", typ)
}

return iarr, nil
}

func handlePropParseError(path []string, err error) error {
if v, ok := err.(*ParseError); ok {
return &ParseError{path: pathFromKeys(path), Cause: v}
Expand Down
124 changes: 116 additions & 8 deletions openapi3filter/testdata/fixtures/petstore.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,98 @@
}
}
},
"/pet/filter": {
"get": {
"tags": [
"pet"
],
"summary": "Finds Pets by status",
"operationId": "filterPets",
"parameters": [
{
"in": "query",
"name": "deepFilter",
"style": "deepObject",
"explode": true,
"allowReserved": true,
"schema": {
"type": "object",
"properties": {
"strings": {
"type": "array",
"items": {
"type": "string"
}
},
"booleans": {
"type": "array",
"items": {
"type": "boolean"
}
},
"numbers": {
"type": "array",
"items": {
"type": "number"
}
},
"integers": {
"type": "array",
"items": {
"type": "integer"
}
}
}
}
}
],
"responses": {
"200": {
"description": "successful operation",
"content": {
"application/xml": {
"schema": {
"type": "array",
"items": {
"allOf": [
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
},
"application/json": {
"schema": {
"type": "array",
"items": {
"allOf": [
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
}
}
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/findByStatus": {
"get": {
"tags": [
Expand Down Expand Up @@ -178,8 +270,12 @@
"type": "array",
"items": {
"allOf": [
{"$ref": "#/components/schemas/Pet"},
{"$ref": "#/components/schemas/PetRequiredProperties"}
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
Expand All @@ -189,8 +285,12 @@
"type": "array",
"items": {
"allOf": [
{"$ref": "#/components/schemas/Pet"},
{"$ref": "#/components/schemas/PetRequiredProperties"}
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
Expand Down Expand Up @@ -283,8 +383,12 @@
"type": "array",
"items": {
"allOf": [
{"$ref": "#/components/schemas/Pet"},
{"$ref": "#/components/schemas/PetRequiredProperties"}
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
Expand All @@ -294,8 +398,12 @@
"type": "array",
"items": {
"allOf": [
{"$ref": "#/components/schemas/Pet"},
{"$ref": "#/components/schemas/PetRequiredProperties"}
{
"$ref": "#/components/schemas/Pet"
},
{
"$ref": "#/components/schemas/PetRequiredProperties"
}
]
}
}
Expand Down

0 comments on commit 05453ef

Please sign in to comment.