Skip to content

Commit 62affaa

Browse files
authored
Fix wrong Found unresolved ref error when converting from Swagger/OpenAPIv2 spec (#237)
1 parent 6a5d509 commit 62affaa

3 files changed

Lines changed: 121 additions & 12 deletions

File tree

openapi2conv/issue187_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package openapi2conv
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"testing"
7+
8+
"github.com/getkin/kin-openapi/openapi2"
9+
"github.com/getkin/kin-openapi/openapi3"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func v2v3(spec2 []byte) (doc3 *openapi3.Swagger, err error) {
14+
var doc2 openapi2.Swagger
15+
if err = json.Unmarshal(spec2, &doc2); err != nil {
16+
return
17+
}
18+
doc3, err = ToV3Swagger(&doc2)
19+
return
20+
}
21+
22+
func TestIssue187(t *testing.T) {
23+
spec := `
24+
{
25+
"swagger": "2.0",
26+
"info": {
27+
"description": "Test Golang Application",
28+
"version": "1.0",
29+
"title": "Test",
30+
"contact": {
31+
"name": "Test",
32+
"email": "test@test.com"
33+
}
34+
},
35+
36+
"paths": {
37+
"/me": {
38+
"get": {
39+
"description": "",
40+
"operationId": "someTest",
41+
"summary": "Some test",
42+
"tags": ["probe"],
43+
"produces": ["application/json"],
44+
"responses": {
45+
"200": {
46+
"description": "successful operation",
47+
"schema": {"$ref": "#/definitions/model.ProductSearchAttributeRequest"}
48+
}
49+
}
50+
}
51+
}
52+
},
53+
54+
"host": "",
55+
"basePath": "/test",
56+
"definitions": {
57+
"model.ProductSearchAttributeRequest": {
58+
"type": "object",
59+
"properties": {
60+
"filterField": {
61+
"type": "string"
62+
},
63+
"filterKey": {
64+
"type": "string"
65+
},
66+
"type": {
67+
"type": "string"
68+
},
69+
"values": {
70+
"$ref": "#/definitions/model.ProductSearchAttributeValueRequest"
71+
}
72+
},
73+
"title": "model.ProductSearchAttributeRequest"
74+
},
75+
"model.ProductSearchAttributeValueRequest": {
76+
"type": "object",
77+
"properties": {
78+
"imageUrl": {
79+
"type": "string"
80+
},
81+
"text": {
82+
"type": "string"
83+
}
84+
},
85+
"title": "model.ProductSearchAttributeValueRequest"
86+
}
87+
}
88+
}
89+
`
90+
doc3, err := v2v3([]byte(spec))
91+
require.NoError(t, err)
92+
93+
spec3, err := json.Marshal(doc3)
94+
require.NoError(t, err)
95+
const expected = `{"components":{"schemas":{"model.ProductSearchAttributeRequest":{"properties":{"filterField":{"type":"string"},"filterKey":{"type":"string"},"type":{"type":"string"},"values":{"$ref":"#/components/schemas/model.ProductSearchAttributeValueRequest"}},"title":"model.ProductSearchAttributeRequest","type":"object"},"model.ProductSearchAttributeValueRequest":{"properties":{"imageUrl":{"type":"string"},"text":{"type":"string"}},"title":"model.ProductSearchAttributeValueRequest","type":"object"}}},"info":{"contact":{"email":"test@test.com","name":"Test"},"description":"Test Golang Application","title":"Test","version":"1.0"},"openapi":"3.0.2","paths":{"/me":{"get":{"operationId":"someTest","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/model.ProductSearchAttributeRequest"}}},"description":"successful operation"}},"summary":"Some test","tags":["probe"]}}}}`
96+
require.Equal(t, string(spec3), expected)
97+
98+
err = doc3.Validate(context.Background())
99+
require.NoError(t, err)
100+
}

openapi2conv/openapi2_conv.go

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
2323
ExtensionProps: swagger.ExtensionProps,
2424
ExternalDocs: swagger.ExternalDocs,
2525
}
26-
host := swagger.Host
27-
if len(host) > 0 {
26+
27+
if host := swagger.Host; len(host) > 0 {
2828
schemes := swagger.Schemes
2929
if len(schemes) == 0 {
30-
schemes = []string{
31-
"https://",
32-
}
30+
schemes = []string{"https://"}
3331
}
3432
basePath := swagger.BasePath
3533
for _, scheme := range schemes {
@@ -38,11 +36,10 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
3836
Host: host,
3937
Path: basePath,
4038
}
41-
result.AddServer(&openapi3.Server{
42-
URL: u.String(),
43-
})
39+
result.AddServer(&openapi3.Server{URL: u.String()})
4440
}
4541
}
42+
4643
if paths := swagger.Paths; paths != nil {
4744
resultPaths := make(map[string]*openapi3.PathItem, len(paths))
4845
for path, pathItem := range paths {
@@ -54,6 +51,7 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
5451
}
5552
result.Paths = resultPaths
5653
}
54+
5755
if parameters := swagger.Parameters; parameters != nil {
5856
result.Components.Parameters = make(map[string]*openapi3.ParameterRef)
5957
result.Components.RequestBodies = make(map[string]*openapi3.RequestBodyRef)
@@ -70,6 +68,7 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
7068
}
7169
}
7270
}
71+
7372
if responses := swagger.Responses; responses != nil {
7473
result.Components.Responses = make(map[string]*openapi3.ResponseRef, len(responses))
7574
for k, response := range responses {
@@ -80,7 +79,9 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
8079
result.Components.Responses[k] = r
8180
}
8281
}
82+
8383
result.Components.Schemas = ToV3Schemas(swagger.Definitions)
84+
8485
if m := swagger.SecurityDefinitions; m != nil {
8586
resultSecuritySchemes := make(map[string]*openapi3.SecuritySchemeRef)
8687
for k, v := range m {
@@ -92,7 +93,15 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
9293
}
9394
result.Components.SecuritySchemes = resultSecuritySchemes
9495
}
96+
9597
result.Security = ToV3SecurityRequirements(swagger.Security)
98+
99+
{
100+
sl := openapi3.NewSwaggerLoader()
101+
if err := sl.ResolveRefsIn(result, nil); err != nil {
102+
return nil, err
103+
}
104+
}
96105
return result, nil
97106
}
98107

@@ -508,7 +517,7 @@ func FromV3SchemaRef(schema *openapi3.SchemaRef) *openapi3.SchemaRef {
508517
return schema
509518
}
510519
if schema.Value.Items != nil {
511-
schema.Value.Items = FromV3SchemaRef((schema.Value.Items))
520+
schema.Value.Items = FromV3SchemaRef(schema.Value.Items)
512521
}
513522
for k, v := range schema.Value.Properties {
514523
schema.Value.Properties[k] = FromV3SchemaRef(v)
@@ -814,7 +823,7 @@ var attemptedBodyParameterNames = []string{
814823
}
815824

816825
func stripNonCustomExtensions(extensions map[string]interface{}) {
817-
for extName, _ := range extensions {
826+
for extName := range extensions {
818827
if !strings.HasPrefix(extName, "x-") {
819828
delete(extensions, extName)
820829
}

openapi3/components.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ func (components *Components) Validate(c context.Context) (err error) {
9292
return
9393
}
9494

95-
const identifierPattern = `^[a-zA-Z0-9.\-_]+$`
95+
const identifierPattern = `^[a-zA-Z0-9._-]+$`
9696

9797
var identifierRegExp = regexp.MustCompile(identifierPattern)
9898

9999
func ValidateIdentifier(value string) error {
100100
if identifierRegExp.MatchString(value) {
101101
return nil
102102
}
103-
return fmt.Errorf("Identifier '%s' is not supported by OpenAPI version 3 standard (regexp: '%s')", value, identifierPattern)
103+
return fmt.Errorf("identifier %q is not supported by OpenAPIv3 standard (regexp: %q)", value, identifierPattern)
104104
}

0 commit comments

Comments
 (0)