Skip to content

Commit af90e9a

Browse files
authored
openapi3filter: Fix default value for array in for query param (#1000)
1 parent d722646 commit af90e9a

File tree

3 files changed

+120
-96
lines changed

3 files changed

+120
-96
lines changed

openapi3filter/issue991_test.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package openapi3filter
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestValidateRequestDefault(t *testing.T) {
13+
const spec = `
14+
openapi: 3.0.0
15+
info:
16+
title: 'Validator'
17+
version: 0.0.1
18+
paths:
19+
/category:
20+
get:
21+
parameters:
22+
- $ref: "#/components/parameters/Type"
23+
responses:
24+
'200':
25+
description: Ok
26+
components:
27+
parameters:
28+
Type:
29+
in: query
30+
name: type
31+
required: false
32+
description: Type parameter
33+
schema:
34+
type: array
35+
default:
36+
- A
37+
- B
38+
- C
39+
items:
40+
type: string
41+
enum:
42+
- A
43+
- B
44+
- C
45+
`
46+
47+
router := setupTestRouter(t, spec)
48+
49+
type args struct {
50+
url string
51+
expected []string
52+
}
53+
tests := []struct {
54+
name string
55+
args args
56+
expectedModification bool
57+
expectedErr error
58+
}{
59+
{
60+
name: "Valid request without type parameters set",
61+
args: args{
62+
url: "/category",
63+
expected: []string{"A", "B", "C"},
64+
},
65+
expectedModification: false,
66+
expectedErr: nil,
67+
},
68+
{
69+
name: "Valid request with 1 type parameters set",
70+
args: args{
71+
url: "/category?type=A",
72+
expected: []string{"A"},
73+
},
74+
expectedModification: false,
75+
expectedErr: nil,
76+
},
77+
{
78+
name: "Valid request with 2 type parameters set",
79+
args: args{
80+
url: "/category?type=A&type=C",
81+
expected: []string{"A", "C"},
82+
},
83+
expectedModification: false,
84+
expectedErr: nil,
85+
},
86+
{
87+
name: "Valid request with 1 type parameters set out of enum",
88+
args: args{
89+
url: "/category?type=X",
90+
expected: nil,
91+
},
92+
expectedModification: false,
93+
expectedErr: &RequestError{},
94+
},
95+
}
96+
for _, tc := range tests {
97+
t.Run(tc.name, func(t *testing.T) {
98+
99+
req, err := http.NewRequest(http.MethodGet, tc.args.url, nil)
100+
require.NoError(t, err)
101+
102+
route, pathParams, err := router.FindRoute(req)
103+
require.NoError(t, err)
104+
105+
validationInput := &RequestValidationInput{
106+
Request: req,
107+
PathParams: pathParams,
108+
Route: route,
109+
}
110+
err = ValidateRequest(context.Background(), validationInput)
111+
assert.IsType(t, tc.expectedErr, err, "ValidateRequest(): error = %v, expectedError %v", err, tc.expectedErr)
112+
if tc.expectedErr != nil {
113+
return
114+
}
115+
116+
assert.Equal(t, tc.args.expected, req.URL.Query()["type"], "ValidateRequest(): query parameter type values do not match expected")
117+
})
118+
}
119+
}

openapi3filter/validate_request.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,7 @@ func appendToQueryValues[T any](q url.Values, parameterName string, v []T) {
114114
// populateDefaultQueryParameters populates default values inside query parameters, while ensuring types are respected
115115
func populateDefaultQueryParameters(q url.Values, parameterName string, value any) {
116116
switch t := value.(type) {
117-
case []string:
118-
appendToQueryValues(q, parameterName, t)
119-
case []float64:
120-
appendToQueryValues(q, parameterName, t)
121-
case []int:
117+
case []interface{}:
122118
appendToQueryValues(q, parameterName, t)
123119
default:
124120
q.Add(parameterName, fmt.Sprintf("%v", value))

openapi3filter/validate_request_test.go

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -567,94 +567,3 @@ paths:
567567
})
568568
require.Error(t, err)
569569
}
570-
571-
var (
572-
StringArraySchemaWithDefault = &openapi3.SchemaRef{
573-
Value: &openapi3.Schema{
574-
Type: &openapi3.Types{"array"},
575-
Items: stringSchema,
576-
Default: []string{"A", "B", "C"},
577-
},
578-
}
579-
FloatArraySchemaWithDefault = &openapi3.SchemaRef{
580-
Value: &openapi3.Schema{
581-
Type: &openapi3.Types{"array"},
582-
Items: numberSchema,
583-
Default: []float64{1.5, 2.5, 3.5},
584-
},
585-
}
586-
)
587-
588-
func TestValidateRequestDefault(t *testing.T) {
589-
type testCase struct {
590-
name string
591-
param *openapi3.Parameter
592-
query string
593-
wantQuery map[string][]string
594-
wantHeader map[string]any
595-
}
596-
597-
testCases := []testCase{
598-
{
599-
name: "String Array In Query",
600-
param: &openapi3.Parameter{
601-
Name: "param", In: "query", Style: "form", Explode: explode,
602-
Schema: StringArraySchemaWithDefault,
603-
},
604-
wantQuery: map[string][]string{
605-
"param": {
606-
"A",
607-
"B",
608-
"C",
609-
},
610-
},
611-
},
612-
{
613-
name: "Float Array In Query",
614-
param: &openapi3.Parameter{
615-
Name: "param", In: "query", Style: "form", Explode: explode,
616-
Schema: FloatArraySchemaWithDefault,
617-
},
618-
wantQuery: map[string][]string{
619-
"param": {
620-
"1.5",
621-
"2.5",
622-
"3.5",
623-
},
624-
},
625-
},
626-
}
627-
628-
for _, tc := range testCases {
629-
t.Run(tc.name, func(t *testing.T) {
630-
info := &openapi3.Info{
631-
Title: "MyAPI",
632-
Version: "0.1",
633-
}
634-
doc := &openapi3.T{OpenAPI: "3.0.0", Info: info, Paths: openapi3.NewPaths()}
635-
op := &openapi3.Operation{
636-
OperationID: "test",
637-
Parameters: []*openapi3.ParameterRef{{Value: tc.param}},
638-
Responses: openapi3.NewResponses(),
639-
}
640-
doc.AddOperation("/test", http.MethodGet, op)
641-
err := doc.Validate(context.Background())
642-
require.NoError(t, err)
643-
router, err := legacyrouter.NewRouter(doc)
644-
require.NoError(t, err)
645-
646-
req, err := http.NewRequest(http.MethodGet, "http://test.org/test?"+tc.query, nil)
647-
route, pathParams, err := router.FindRoute(req)
648-
require.NoError(t, err)
649-
650-
input := &RequestValidationInput{Request: req, PathParams: pathParams, Route: route}
651-
652-
err = ValidateParameter(context.Background(), input, tc.param)
653-
require.NoError(t, err)
654-
655-
for k, v := range tc.wantQuery {
656-
require.Equal(t, v, input.Request.URL.Query()[k])
657-
}
658-
})
659-
}
660-
}

0 commit comments

Comments
 (0)