Skip to content

Commit

Permalink
openapi3: handle refs missing fragment (#511)
Browse files Browse the repository at this point in the history
  • Loading branch information
fenollp authored Nov 26, 2023
1 parent bd3ac0e commit 582e6d0
Show file tree
Hide file tree
Showing 3 changed files with 301 additions and 1 deletion.
157 changes: 157 additions & 0 deletions openapi3/issue495_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package openapi3

import (
"testing"

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

func TestIssue495(t *testing.T) {
{
spec := []byte(`
openapi: 3.0.1
info:
version: v1
title: Products api
components:
schemas:
someSchema:
type: object
schemaArray:
type: array
minItems: 1
items:
$ref: '#'
paths:
/categories:
get:
responses:
'200':
description: ''
content:
application/json:
schema:
properties:
allOf:
$ref: '#/components/schemas/schemaArray'
`[1:])

sl := NewLoader()

doc, err := sl.LoadFromData(spec)
require.NoError(t, err)

err = doc.Validate(sl.Context)
require.EqualError(t, err, `invalid components: schema "schemaArray": found unresolved ref: "#"`)
}

spec := []byte(`
openapi: 3.0.1
info:
version: v1
title: Products api
components:
schemas:
someSchema:
type: object
schemaArray:
type: array
minItems: 1
items:
$ref: '#/components/schemas/someSchema'
paths:
/categories:
get:
responses:
'200':
description: ''
content:
application/json:
schema:
properties:
allOf:
$ref: '#/components/schemas/schemaArray'
`[1:])

sl := NewLoader()

doc, err := sl.LoadFromData(spec)
require.NoError(t, err)

err = doc.Validate(sl.Context)
require.NoError(t, err)

require.Equal(t, &Schema{Type: "object"}, doc.Components.Schemas["schemaArray"].Value.Items.Value)
}

func TestIssue495WithDraft04(t *testing.T) {
spec := []byte(`
openapi: 3.0.1
servers:
- url: http://localhost:5000
info:
version: v1
title: Products api
contact:
name: me
email: me@github.com
description: This is a sample
paths:
/categories:
get:
summary: Provides the available categories for the store
operationId: list-categories
responses:
'200':
description: this is a desc
content:
application/json:
schema:
$ref: http://json-schema.org/draft-04/schema
`[1:])

sl := NewLoader()
sl.IsExternalRefsAllowed = true

doc, err := sl.LoadFromData(spec)
require.NoError(t, err)

err = doc.Validate(sl.Context)
require.ErrorContains(t, err, `found unresolved ref: "#"`)
}

func TestIssue495WithDraft04Bis(t *testing.T) {
spec := []byte(`
openapi: 3.0.1
servers:
- url: http://localhost:5000
info:
version: v1
title: Products api
contact:
name: me
email: me@github.com
description: This is a sample
paths:
/categories:
get:
summary: Provides the available categories for the store
operationId: list-categories
responses:
'200':
description: this is a desc
content:
application/json:
schema:
$ref: testdata/draft04.yml
`[1:])

sl := NewLoader()
sl.IsExternalRefsAllowed = true

doc, err := sl.LoadFromData(spec)
require.NoError(t, err)

err = doc.Validate(sl.Context)
require.ErrorContains(t, err, `found unresolved ref: "#"`)
}
5 changes: 4 additions & 1 deletion openapi3/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,10 @@ func (loader *Loader) resolveComponent(doc *T, ref string, path *url.URL, resolv
return nil, nil, fmt.Errorf("cannot parse reference: %q: %v", ref, parsedURL)
}
fragment := parsedURL.Fragment
if !strings.HasPrefix(fragment, "/") {
if fragment == "" {
fragment = "/"
}
if fragment[0] != '/' {
return nil, nil, fmt.Errorf("expected fragment prefix '#/' in URI %q", ref)
}

Expand Down
140 changes: 140 additions & 0 deletions openapi3/testdata/draft04.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
id: http://json-schema.org/draft-04/schema#
$schema: http://json-schema.org/draft-04/schema#
description: Core schema meta-schema
definitions:
schemaArray:
type: array
minItems: 1
items:
$ref: '#'
positiveInteger:
type: integer
minimum: 0
positiveIntegerDefault0:
allOf:
- $ref: '#/definitions/positiveInteger'
- default: 0
simpleTypes:
enum:
- array
- boolean
- integer
- 'null'
- number
- object
- string
stringArray:
type: array
items:
type: string
minItems: 1
uniqueItems: true
type: object
properties:
id:
type: string
$schema:
type: string
title:
type: string
description:
type: string
default: {}
multipleOf:
type: number
minimum: 0
exclusiveMinimum: true
maximum:
type: number
exclusiveMaximum:
type: boolean
default: false
minimum:
type: number
exclusiveMinimum:
type: boolean
default: false
maxLength:
$ref: '#/definitions/positiveInteger'
minLength:
$ref: '#/definitions/positiveIntegerDefault0'
pattern:
type: string
format: regex
additionalItems:
anyOf:
- type: boolean
- $ref: '#'
default: {}
items:
anyOf:
- $ref: '#'
- $ref: '#/definitions/schemaArray'
default: {}
maxItems:
$ref: '#/definitions/positiveInteger'
minItems:
$ref: '#/definitions/positiveIntegerDefault0'
uniqueItems:
type: boolean
default: false
maxProperties:
$ref: '#/definitions/positiveInteger'
minProperties:
$ref: '#/definitions/positiveIntegerDefault0'
required:
$ref: '#/definitions/stringArray'
additionalProperties:
anyOf:
- type: boolean
- $ref: '#'
default: {}
definitions:
type: object
additionalProperties:
$ref: '#'
default: {}
properties:
type: object
additionalProperties:
$ref: '#'
default: {}
patternProperties:
type: object
additionalProperties:
'$ref': '#'
default: {}
dependencies:
type: object
additionalProperties:
anyOf:
- $ref: '#'
- $ref: '#/definitions/stringArray'
enum:
type: array
minItems: 1
uniqueItems: true
type:
anyOf:
- $ref: '#/definitions/simpleTypes'
- type: array
items:
$ref: '#/definitions/simpleTypes'
minItems: 1
uniqueItems: true
format:
type: string
allOf:
$ref: '#/definitions/schemaArray'
anyOf:
$ref: '#/definitions/schemaArray'
oneOf:
$ref: '#/definitions/schemaArray'
not:
$ref: '#'
dependencies:
exclusiveMaximum:
- maximum
exclusiveMinimum:
- minimum
default: {}

0 comments on commit 582e6d0

Please sign in to comment.