Skip to content

Commit

Permalink
openapi3filter: Fix default value for array in for query param (#1000)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tommy-42 authored Aug 2, 2024
1 parent d722646 commit af90e9a
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 96 deletions.
119 changes: 119 additions & 0 deletions openapi3filter/issue991_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package openapi3filter

import (
"context"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestValidateRequestDefault(t *testing.T) {
const spec = `
openapi: 3.0.0
info:
title: 'Validator'
version: 0.0.1
paths:
/category:
get:
parameters:
- $ref: "#/components/parameters/Type"
responses:
'200':
description: Ok
components:
parameters:
Type:
in: query
name: type
required: false
description: Type parameter
schema:
type: array
default:
- A
- B
- C
items:
type: string
enum:
- A
- B
- C
`

router := setupTestRouter(t, spec)

type args struct {
url string
expected []string
}
tests := []struct {
name string
args args
expectedModification bool
expectedErr error
}{
{
name: "Valid request without type parameters set",
args: args{
url: "/category",
expected: []string{"A", "B", "C"},
},
expectedModification: false,
expectedErr: nil,
},
{
name: "Valid request with 1 type parameters set",
args: args{
url: "/category?type=A",
expected: []string{"A"},
},
expectedModification: false,
expectedErr: nil,
},
{
name: "Valid request with 2 type parameters set",
args: args{
url: "/category?type=A&type=C",
expected: []string{"A", "C"},
},
expectedModification: false,
expectedErr: nil,
},
{
name: "Valid request with 1 type parameters set out of enum",
args: args{
url: "/category?type=X",
expected: nil,
},
expectedModification: false,
expectedErr: &RequestError{},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {

req, err := http.NewRequest(http.MethodGet, tc.args.url, nil)
require.NoError(t, err)

route, pathParams, err := router.FindRoute(req)
require.NoError(t, err)

validationInput := &RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
}
err = ValidateRequest(context.Background(), validationInput)
assert.IsType(t, tc.expectedErr, err, "ValidateRequest(): error = %v, expectedError %v", err, tc.expectedErr)
if tc.expectedErr != nil {
return
}

assert.Equal(t, tc.args.expected, req.URL.Query()["type"], "ValidateRequest(): query parameter type values do not match expected")
})
}
}
6 changes: 1 addition & 5 deletions openapi3filter/validate_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,7 @@ func appendToQueryValues[T any](q url.Values, parameterName string, v []T) {
// populateDefaultQueryParameters populates default values inside query parameters, while ensuring types are respected
func populateDefaultQueryParameters(q url.Values, parameterName string, value any) {
switch t := value.(type) {
case []string:
appendToQueryValues(q, parameterName, t)
case []float64:
appendToQueryValues(q, parameterName, t)
case []int:
case []interface{}:
appendToQueryValues(q, parameterName, t)
default:
q.Add(parameterName, fmt.Sprintf("%v", value))
Expand Down
91 changes: 0 additions & 91 deletions openapi3filter/validate_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,94 +567,3 @@ paths:
})
require.Error(t, err)
}

var (
StringArraySchemaWithDefault = &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: &openapi3.Types{"array"},
Items: stringSchema,
Default: []string{"A", "B", "C"},
},
}
FloatArraySchemaWithDefault = &openapi3.SchemaRef{
Value: &openapi3.Schema{
Type: &openapi3.Types{"array"},
Items: numberSchema,
Default: []float64{1.5, 2.5, 3.5},
},
}
)

func TestValidateRequestDefault(t *testing.T) {
type testCase struct {
name string
param *openapi3.Parameter
query string
wantQuery map[string][]string
wantHeader map[string]any
}

testCases := []testCase{
{
name: "String Array In Query",
param: &openapi3.Parameter{
Name: "param", In: "query", Style: "form", Explode: explode,
Schema: StringArraySchemaWithDefault,
},
wantQuery: map[string][]string{
"param": {
"A",
"B",
"C",
},
},
},
{
name: "Float Array In Query",
param: &openapi3.Parameter{
Name: "param", In: "query", Style: "form", Explode: explode,
Schema: FloatArraySchemaWithDefault,
},
wantQuery: map[string][]string{
"param": {
"1.5",
"2.5",
"3.5",
},
},
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
info := &openapi3.Info{
Title: "MyAPI",
Version: "0.1",
}
doc := &openapi3.T{OpenAPI: "3.0.0", Info: info, Paths: openapi3.NewPaths()}
op := &openapi3.Operation{
OperationID: "test",
Parameters: []*openapi3.ParameterRef{{Value: tc.param}},
Responses: openapi3.NewResponses(),
}
doc.AddOperation("/test", http.MethodGet, op)
err := doc.Validate(context.Background())
require.NoError(t, err)
router, err := legacyrouter.NewRouter(doc)
require.NoError(t, err)

req, err := http.NewRequest(http.MethodGet, "http://test.org/test?"+tc.query, nil)
route, pathParams, err := router.FindRoute(req)
require.NoError(t, err)

input := &RequestValidationInput{Request: req, PathParams: pathParams, Route: route}

err = ValidateParameter(context.Background(), input, tc.param)
require.NoError(t, err)

for k, v := range tc.wantQuery {
require.Equal(t, v, input.Request.URL.Query()[k])
}
})
}
}

0 comments on commit af90e9a

Please sign in to comment.