Skip to content

Commit eac89ec

Browse files
authored
handle digits in $ref.s (#213)
1 parent 0d3735e commit eac89ec

3 files changed

Lines changed: 113 additions & 6 deletions

File tree

openapi2conv/openapi2_conv.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/getkin/kin-openapi/openapi3"
1212
)
1313

14+
// ToV3Swagger converts an OpenAPIv2 spec to an OpenAPIv3 spec
1415
func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
1516
result := &openapi3.Swagger{
1617
OpenAPI: "3.0.2",
@@ -396,8 +397,7 @@ func FromV3Swagger(swagger *openapi3.Swagger) (*openapi2.Swagger, error) {
396397
}
397398
result.Parameters = map[string]*openapi2.Parameter{}
398399
for name, param := range swagger.Components.Parameters {
399-
result.Parameters[name], err = FromV3Parameter(param)
400-
if err != nil {
400+
if result.Parameters[name], err = FromV3Parameter(param); err != nil {
401401
return nil, err
402402
}
403403
}

openapi3/swagger_loader.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"net/url"
1111
"path"
1212
"reflect"
13+
"strconv"
1314
"strings"
1415

1516
"github.com/ghodss/yaml"
@@ -285,16 +286,25 @@ func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref strin
285286
}
286287

287288
func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, error) {
288-
val := reflect.Indirect(reflect.ValueOf(cursor))
289-
290-
switch val.Kind() {
289+
switch val := reflect.Indirect(reflect.ValueOf(cursor)); val.Kind() {
291290
case reflect.Map:
292291
elementValue := val.MapIndex(reflect.ValueOf(fieldName))
293292
if !elementValue.IsValid() {
294293
return nil, fmt.Errorf("Map key not found: %v", fieldName)
295294
}
296295
return elementValue.Interface(), nil
297296

297+
case reflect.Slice:
298+
i, err := strconv.ParseUint(fieldName, 10, 32)
299+
if err != nil {
300+
return nil, err
301+
}
302+
index := int(i)
303+
if index >= val.Len() {
304+
return nil, errors.New("slice index out of bounds")
305+
}
306+
return val.Index(index).Interface(), nil
307+
298308
case reflect.Struct:
299309
for i := 0; i < val.NumField(); i++ {
300310
field := val.Type().Field(i)
@@ -311,8 +321,10 @@ func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, e
311321
}
312322
// give up
313323
return nil, fmt.Errorf("Struct field not found: %v", fieldName)
324+
325+
default:
326+
return nil, errors.New("not a map, slice nor struct")
314327
}
315-
return nil, errors.New("Not a map or struct")
316328
}
317329

318330
func (swaggerLoader *SwaggerLoader) resolveRefSwagger(swagger *Swagger, ref string, path *url.URL) (*Swagger, string, *url.URL, error) {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package openapi3
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
func TestIssue212(t *testing.T) {
11+
spec := `
12+
openapi: 3.0.1
13+
info:
14+
title: 'test'
15+
version: 1.0.0
16+
servers:
17+
- url: /api
18+
19+
paths:
20+
/available-products:
21+
get:
22+
operationId: getAvailableProductCollection
23+
responses:
24+
"200":
25+
description: test
26+
content:
27+
application/json:
28+
schema:
29+
type: array
30+
items:
31+
$ref: "#/components/schemas/AvailableProduct"
32+
33+
components:
34+
schemas:
35+
AvailableProduct:
36+
type: object
37+
properties:
38+
id:
39+
type: string
40+
type:
41+
type: string
42+
name:
43+
type: string
44+
media:
45+
type: object
46+
properties:
47+
documents:
48+
type: array
49+
items:
50+
allOf:
51+
- $ref: "#/components/schemas/AvailableProduct/properties/previewImage/allOf/0"
52+
- type: object
53+
properties:
54+
uri:
55+
type: string
56+
pattern: ^\/documents\/[0-9a-f]{64}$
57+
previewImage:
58+
allOf:
59+
- type: object
60+
required:
61+
- id
62+
- uri
63+
properties:
64+
id:
65+
type: string
66+
uri:
67+
type: string
68+
- type: object
69+
properties:
70+
uri:
71+
type: string
72+
pattern: ^\/images\/[0-9a-f]{64}$
73+
`
74+
75+
loader := NewSwaggerLoader()
76+
doc, err := loader.LoadSwaggerFromData([]byte(spec))
77+
require.NoError(t, err)
78+
err = doc.Validate(loader.Context)
79+
require.NoError(t, err)
80+
81+
expected, err := json.Marshal(&Schema{
82+
Type: "object",
83+
Required: []string{"id", "uri"},
84+
Properties: map[string]*SchemaRef{
85+
"id": {Value: &Schema{Type: "string"}},
86+
"uri": {Value: &Schema{Type: "string"}},
87+
},
88+
},
89+
)
90+
require.NoError(t, err)
91+
got, err := json.Marshal(doc.Components.Schemas["AvailableProduct"].Value.Properties["media"].Value.Properties["documents"].Value.Items.Value.AllOf[0].Value)
92+
require.NoError(t, err)
93+
94+
require.Equal(t, expected, got)
95+
}

0 commit comments

Comments
 (0)