Skip to content

Commit

Permalink
Correctly resolve path of yaml resource if double referenced. (#611)
Browse files Browse the repository at this point in the history
  • Loading branch information
d-sauer authored Oct 7, 2022
1 parent fa5d9a9 commit db52673
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 9 deletions.
16 changes: 8 additions & 8 deletions openapi3/internalize_refs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package openapi3

import (
"context"
"io/ioutil"
"os"
"regexp"
"testing"

Expand Down Expand Up @@ -41,25 +41,25 @@ func TestInternalizeRefs(t *testing.T) {
err = doc.Validate(ctx)
require.NoError(t, err, "validating internalized spec")

data, err := doc.MarshalJSON()
actual, err := doc.MarshalJSON()
require.NoError(t, err, "marshalling internalized spec")

// run a static check over the file, making sure each occurence of a
// reference is followed by a #
numRefs := len(regexpRef.FindAll(data, -1))
numInternalRefs := len(regexpRefInternal.FindAll(data, -1))
numRefs := len(regexpRef.FindAll(actual, -1))
numInternalRefs := len(regexpRefInternal.FindAll(actual, -1))
require.Equal(t, numRefs, numInternalRefs, "checking all references are internal")

// load from data, but with the path set to the current directory
doc2, err := sl.LoadFromData(data)
// load from actual, but with the path set to the current directory
doc2, err := sl.LoadFromData(actual)
require.NoError(t, err, "reloading spec")
err = doc2.Validate(ctx)
require.NoError(t, err, "validating reloaded spec")

// compare with expected
data0, err := ioutil.ReadFile(test.filename + ".internalized.yml")
expected, err := os.ReadFile(test.filename + ".internalized.yml")
require.NoError(t, err)
require.JSONEq(t, string(data), string(data0))
require.JSONEq(t, string(expected), string(actual))
})
}
}
9 changes: 8 additions & 1 deletion openapi3/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ type Loader struct {

Context context.Context

rootDir string
rootDir string
rootLocation string

visitedPathItemRefs map[string]struct{}

Expand Down Expand Up @@ -148,6 +149,7 @@ func (loader *Loader) LoadFromDataWithPath(data []byte, location *url.URL) (*T,
func (loader *Loader) loadFromDataWithPathInternal(data []byte, location *url.URL) (*T, error) {
if loader.visitedDocuments == nil {
loader.visitedDocuments = make(map[string]*T)
loader.rootLocation = location.Path
}
uri := location.String()
if doc, ok := loader.visitedDocuments[uri]; ok {
Expand Down Expand Up @@ -420,6 +422,11 @@ func (loader *Loader) documentPathForRecursiveRef(current *url.URL, resolvedRef
if loader.rootDir == "" {
return current
}

if resolvedRef == "" {
return &url.URL{Path: loader.rootLocation}
}

return &url.URL{Path: path.Join(loader.rootDir, resolvedRef)}
}

Expand Down
2 changes: 2 additions & 0 deletions openapi3/loader_recursive_ref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ func TestLoaderSupportsRecursiveReference(t *testing.T) {
err = doc.Validate(loader.Context)
require.NoError(t, err)
require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Example)
require.Equal(t, "ErrorDetails", doc.Paths["/foo"].Get.Responses.Get(400).Value.Content.Get("application/json").Schema.Value.Title)
require.Equal(t, "ErrorDetails", doc.Paths["/double-ref-foo"].Get.Responses.Get(400).Value.Content.Get("application/json").Schema.Value.Title)
}

func TestIssue447(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions openapi3/testdata/recursiveRef/components/models/error.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
type: object
title: ErrorDetails
16 changes: 16 additions & 0 deletions openapi3/testdata/recursiveRef/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ info:
paths:
/foo:
$ref: ./paths/foo.yml
/double-ref-foo:
get:
summary: Double ref response
description: Reference response with double reference.
responses:
"400":
$ref: "#/components/responses/400"
components:
schemas:
Foo:
Expand All @@ -15,3 +22,12 @@ components:
$ref: ./components/Bar.yml
Cat:
$ref: ./components/Cat.yml
Error:
$ref: ./components/models/error.yaml
responses:
"400":
description: 400 Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
34 changes: 34 additions & 0 deletions openapi3/testdata/recursiveRef/openapi.yml.internalized.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@
}
}
},
"responses": {
"400": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"description": "400 Bad Request"
}
},
"schemas": {
"Bar": {
"example": "bar",
"type": "string"
},
"Error":{
"title":"ErrorDetails",
"type":"object"
},
"Foo": {
"properties": {
"bar": {
Expand All @@ -30,6 +46,10 @@
},
"type": "object"
},
"error":{
"title":"ErrorDetails",
"type":"object"
},
"Cat": {
"properties": {
"cat": {
Expand All @@ -46,6 +66,17 @@
},
"openapi": "3.0.3",
"paths": {
"/double-ref-foo": {
"get": {
"description": "Reference response with double reference.",
"responses": {
"400": {
"$ref": "#/components/responses/400"
}
},
"summary": "Double ref response"
}
},
"/foo": {
"get": {
"responses": {
Expand All @@ -63,6 +94,9 @@
}
},
"description": "OK"
},
"400": {
"$ref": "#/components/responses/400"
}
}
},
Expand Down
2 changes: 2 additions & 0 deletions openapi3/testdata/recursiveRef/paths/foo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ get:
properties:
foo2:
$ref: ../openapi.yml#/components/schemas/Foo2
"400":
$ref: "../openapi.yml#/components/responses/400"

0 comments on commit db52673

Please sign in to comment.