Skip to content

Commit 6e233af

Browse files
authored
openapi3: fix integer enum schema validation after json.Number PR (#755)
1 parent 84703aa commit 6e233af

File tree

2 files changed

+189
-2
lines changed

2 files changed

+189
-2
lines changed

openapi3/schema.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,20 @@ func (schema *Schema) visitJSON(settings *schemaValidationSettings, value interf
11431143
func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, value interface{}) (err error) {
11441144
if enum := schema.Enum; len(enum) != 0 {
11451145
for _, v := range enum {
1146-
if reflect.DeepEqual(v, value) {
1147-
return
1146+
switch c := value.(type) {
1147+
case json.Number:
1148+
var f float64
1149+
f, err = strconv.ParseFloat(c.String(), 64)
1150+
if err != nil {
1151+
return err
1152+
}
1153+
if v == f {
1154+
return
1155+
}
1156+
default:
1157+
if reflect.DeepEqual(v, value) {
1158+
return
1159+
}
11481160
}
11491161
}
11501162
if settings.failfast {
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package openapi3filter
2+
3+
import (
4+
"bytes"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/getkin/kin-openapi/openapi3"
11+
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
12+
)
13+
14+
func TestValidationWithIntegerEnum(t *testing.T) {
15+
const spec = `
16+
openapi: 3.0.0
17+
info:
18+
title: Example integer enum
19+
version: '0.1'
20+
paths:
21+
/sample:
22+
put:
23+
requestBody:
24+
required: true
25+
content:
26+
application/json:
27+
schema:
28+
type: object
29+
properties:
30+
exenum:
31+
type: integer
32+
enum:
33+
- 0
34+
- 1
35+
- 2
36+
- 3
37+
example: 0
38+
nullable: true
39+
responses:
40+
'200':
41+
description: Ok
42+
`
43+
44+
loader := openapi3.NewLoader()
45+
doc, err := loader.LoadFromData([]byte(spec))
46+
require.NoError(t, err)
47+
48+
router, err := legacyrouter.NewRouter(doc)
49+
require.NoError(t, err)
50+
51+
tests := []struct {
52+
data []byte
53+
wantErr bool
54+
}{
55+
{
56+
[]byte(`{"exenum": 1}`),
57+
false,
58+
},
59+
{
60+
[]byte(`{"exenum": "1"}`),
61+
true,
62+
},
63+
{
64+
[]byte(`{"exenum": null}`),
65+
false,
66+
},
67+
{
68+
[]byte(`{}`),
69+
false,
70+
},
71+
}
72+
73+
for _, tt := range tests {
74+
body := bytes.NewReader(tt.data)
75+
req, err := http.NewRequest("PUT", "/sample", body)
76+
require.NoError(t, err)
77+
req.Header.Add(headerCT, "application/json")
78+
79+
route, pathParams, err := router.FindRoute(req)
80+
require.NoError(t, err)
81+
82+
requestValidationInput := &RequestValidationInput{
83+
Request: req,
84+
PathParams: pathParams,
85+
Route: route,
86+
}
87+
err = ValidateRequest(loader.Context, requestValidationInput)
88+
if tt.wantErr {
89+
require.Error(t, err)
90+
} else {
91+
require.NoError(t, err)
92+
}
93+
}
94+
}
95+
96+
func TestValidationWithStringEnum(t *testing.T) {
97+
const spec = `
98+
openapi: 3.0.0
99+
info:
100+
title: Example string enum
101+
version: '0.1'
102+
paths:
103+
/sample:
104+
put:
105+
requestBody:
106+
required: true
107+
content:
108+
application/json:
109+
schema:
110+
type: object
111+
properties:
112+
exenum:
113+
type: string
114+
enum:
115+
- "0"
116+
- "1"
117+
- "2"
118+
- "3"
119+
example: "0"
120+
responses:
121+
'200':
122+
description: Ok
123+
`
124+
125+
loader := openapi3.NewLoader()
126+
doc, err := loader.LoadFromData([]byte(spec))
127+
require.NoError(t, err)
128+
129+
router, err := legacyrouter.NewRouter(doc)
130+
require.NoError(t, err)
131+
132+
tests := []struct {
133+
data []byte
134+
wantErr bool
135+
}{
136+
{
137+
[]byte(`{"exenum": "1"}`),
138+
false,
139+
},
140+
{
141+
[]byte(`{"exenum": 1}`),
142+
true,
143+
},
144+
{
145+
[]byte(`{"exenum": null}`),
146+
true,
147+
},
148+
{
149+
[]byte(`{}`),
150+
false,
151+
},
152+
}
153+
154+
for _, tt := range tests {
155+
body := bytes.NewReader(tt.data)
156+
req, err := http.NewRequest("PUT", "/sample", body)
157+
require.NoError(t, err)
158+
req.Header.Add(headerCT, "application/json")
159+
160+
route, pathParams, err := router.FindRoute(req)
161+
require.NoError(t, err)
162+
163+
requestValidationInput := &RequestValidationInput{
164+
Request: req,
165+
PathParams: pathParams,
166+
Route: route,
167+
}
168+
err = ValidateRequest(loader.Context, requestValidationInput)
169+
if tt.wantErr {
170+
require.Error(t, err)
171+
} else {
172+
require.NoError(t, err)
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)