Skip to content

Commit a799261

Browse files
Merge pull request #235 from cerberauth/fix-openapi-media-types-and-params
fix: manage openapi wrongly parsed example params and unsupported media types
2 parents 5df3881 + 62aaa61 commit a799261

File tree

5 files changed

+1476
-70
lines changed

5 files changed

+1476
-70
lines changed

.github/workflows/scans.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ jobs:
319319
"simple_http_bearer_jwt.openapi.json",
320320
"simple_http_bearer.openapi.json",
321321
"complex.openapi.json",
322+
"petstore.openapi.json"
322323
]
323324

324325
steps:

openapi/operation.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ func (openapi *OpenAPI) Operations(client *request.Client, securitySchemes auth.
8484
var body *bytes.Buffer
8585
var mediaType string
8686
if o.RequestBody != nil {
87-
body, mediaType = getRequestBodyValue(o.RequestBody.Value)
87+
body, mediaType, _ = getRequestBodyValue(o.RequestBody.Value)
88+
}
89+
if body != nil && mediaType != "" {
8890
header.Set("Content-Type", mediaType)
8991
} else {
9092
body = bytes.NewBuffer(nil)

openapi/param.go

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package openapi
22

33
import (
44
"bytes"
5+
"fmt"
56
"strconv"
67

78
"github.com/brianvoe/gofakeit/v7"
@@ -10,21 +11,37 @@ import (
1011

1112
const maximumDepth = 4
1213

14+
const (
15+
FloatParamType = "float"
16+
DoubleParamType = "double"
17+
Int32ParamFormat = "int32"
18+
Int64ParamFormat = "int64"
19+
)
20+
21+
func NewErrNoSupportedBodyMediaType() error {
22+
return fmt.Errorf("no supported body media type")
23+
}
24+
1325
func getParameterValue(param *openapi3.Parameter) string {
1426
if param.Schema != nil {
1527
value := getSchemaValue(param.Schema.Value, 0)
1628
switch {
1729
case param.Schema.Value.Type.Is("string"):
1830
return value.(string)
1931
case param.Schema.Value.Type.Is("number"):
20-
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
32+
switch param.Schema.Value.Format {
33+
case FloatParamType:
34+
return strconv.FormatFloat(value.(float64), 'f', -1, 32)
35+
case DoubleParamType:
36+
default:
37+
return strconv.FormatFloat(value.(float64), 'f', -1, 64)
38+
}
2139
case param.Schema.Value.Type.Is("integer"):
22-
return strconv.Itoa(value.(int))
40+
return strconv.FormatInt(value.(int64), 10)
2341
case param.Schema.Value.Type.Is("boolean"):
2442
return strconv.FormatBool(value.(bool))
2543
}
2644
}
27-
2845
return ""
2946
}
3047

@@ -36,7 +53,7 @@ func mapRequestBodyFakeValueToJSON(schema *openapi3.Schema, fakeValue interface{
3653
case schema.Type.Is("number"):
3754
jsonResponse = []byte(strconv.FormatFloat(fakeValue.(float64), 'f', -1, 64))
3855
case schema.Type.Is("integer"):
39-
jsonResponse = []byte(strconv.Itoa(fakeValue.(int)))
56+
jsonResponse = []byte(strconv.FormatInt(fakeValue.(int64), 10))
4057
case schema.Type.Is("boolean"):
4158
jsonResponse = []byte(strconv.FormatBool(fakeValue.(bool)))
4259
case schema.Type.Is("array"):
@@ -64,35 +81,83 @@ func mapRequestBodyFakeValueToJSON(schema *openapi3.Schema, fakeValue interface{
6481
return bytes.NewBuffer(jsonResponse)
6582
}
6683

67-
func getRequestBodyValue(requestBody *openapi3.RequestBody) (*bytes.Buffer, string) {
68-
if requestBody.Content != nil {
69-
for mediaType, mediaTypeValue := range requestBody.Content {
70-
if mediaTypeValue.Schema != nil {
71-
body := getSchemaValue(mediaTypeValue.Schema.Value, 0)
72-
switch mediaType {
73-
case "application/json":
74-
return mapRequestBodyFakeValueToJSON(mediaTypeValue.Schema.Value, body), "application/json"
75-
default:
76-
return bytes.NewBuffer([]byte(body.(string))), mediaType
77-
}
84+
func getRequestBodyValue(requestBody *openapi3.RequestBody) (*bytes.Buffer, string, error) {
85+
if requestBody == nil || requestBody.Content == nil {
86+
return nil, "", nil
87+
}
88+
for mediaType, mediaTypeValue := range requestBody.Content {
89+
if mediaTypeValue.Schema != nil {
90+
body := getSchemaValue(mediaTypeValue.Schema.Value, 0)
91+
if mediaType == "application/json" {
92+
return mapRequestBodyFakeValueToJSON(mediaTypeValue.Schema.Value, body), mediaType, nil
7893
}
7994
}
8095
}
81-
82-
return bytes.NewBuffer(nil), ""
96+
return nil, "", NewErrNoSupportedBodyMediaType()
8397
}
8498

85-
func getSchemaValue(schema *openapi3.Schema, depth int) interface{} {
99+
func parseSchemaExample(schema *openapi3.Schema) (interface{}, error) {
100+
var example interface{}
86101
if schema.Example != nil {
87-
return schema.Example
102+
example = schema.Example
88103
} else if len(schema.Enum) > 0 {
89-
return schema.Enum[gofakeit.Number(0, len(schema.Enum)-1)]
104+
example = schema.Enum[gofakeit.Number(0, len(schema.Enum)-1)]
105+
}
106+
if example == nil {
107+
return nil, nil
108+
}
109+
110+
var ok bool
111+
_, ok = example.(string)
112+
if ok && !schema.Type.Is("string") {
113+
switch {
114+
case schema.Type.Is("number"):
115+
return strconv.ParseFloat(example.(string), 64)
116+
case schema.Type.Is("integer"):
117+
return strconv.ParseInt(example.(string), 10, 64)
118+
case schema.Type.Is("boolean"):
119+
return strconv.ParseBool(example.(string))
120+
}
121+
}
122+
123+
switch {
124+
case schema.Type.Is("string"):
125+
example, ok = example.(string)
126+
case schema.Type.Is("number"):
127+
example, ok = example.(float64)
128+
case schema.Type.Is("integer"):
129+
switch schema.Format {
130+
case Int32ParamFormat:
131+
example, ok = example.(int32)
132+
case Int64ParamFormat:
133+
default:
134+
example, ok = example.(int64)
135+
}
136+
case schema.Type.Is("boolean"):
137+
example, ok = example.(bool)
138+
case schema.Type.Is("array"):
139+
example, ok = example.([]interface{})
140+
case schema.Type.Is("object"):
141+
example, ok = example.(map[string]interface{})
142+
}
143+
if !ok {
144+
return nil, fmt.Errorf("invalid example type")
145+
}
146+
return example, nil
147+
}
148+
149+
func getSchemaValue(schema *openapi3.Schema, depth int) interface{} {
150+
example, err := parseSchemaExample(schema)
151+
if err == nil && example != nil {
152+
return example
90153
}
91154

92155
// if there is no example generate random param
93156
switch {
94-
case schema.Type.Is("number") || schema.Type.Is("integer"):
95-
return gofakeit.Number(0, 10)
157+
case schema.Type.Is("number"):
158+
return gofakeit.Float64()
159+
case schema.Type.Is("integer"):
160+
return gofakeit.Int64()
96161
case schema.Type.Is("boolean"):
97162
return gofakeit.Bool()
98163
case schema.Type.Is("array"):

0 commit comments

Comments
 (0)