diff --git a/openapi3/loader.go b/openapi3/loader.go index 9ed8e3076..637e1acf9 100644 --- a/openapi3/loader.go +++ b/openapi3/loader.go @@ -790,6 +790,10 @@ func (loader *Loader) resolveSchemaRef(doc *T, component *SchemaRef, documentPat func (loader *Loader) getResolvedRefPath(ref string, resolved *SchemaRef, cur, found *url.URL) string { if referencedFilename := strings.Split(ref, "#")[0]; referencedFilename == "" { if cur != nil { + if loader.rootDir != "" && strings.HasPrefix(cur.Path, loader.rootDir) { + return cur.Path[len(loader.rootDir)+1:] + } + return path.Base(cur.Path) } return "" diff --git a/openapi3/loader_test.go b/openapi3/loader_test.go index d492e2471..684e1b44d 100644 --- a/openapi3/loader_test.go +++ b/openapi3/loader_test.go @@ -263,6 +263,17 @@ func TestLoadWithReferenceInReference(t *testing.T) { require.Equal(t, "string", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["definition_reference"].Value.Type) } +func TestLoadWithReferenceInReferenceInProperty(t *testing.T) { + loader := NewLoader() + loader.IsExternalRefsAllowed = true + doc, err := loader.LoadFromFile("testdata/refInRefInProperty/openapi.yaml") + require.NoError(t, err) + require.NotNil(t, doc) + err = doc.Validate(loader.Context) + require.NoError(t, err) + require.Equal(t, "Problem details", doc.Paths["/api/test/ref/in/ref/in/property"].Post.Responses["401"].Value.Content["application/json"].Schema.Value.Properties["error"].Value.Title) +} + func TestLoadFileWithExternalSchemaRef(t *testing.T) { loader := NewLoader() loader.IsExternalRefsAllowed = true diff --git a/openapi3/testdata/refInRefInProperty/common-data-objects/problem-details-0.0.1.schema.json b/openapi3/testdata/refInRefInProperty/common-data-objects/problem-details-0.0.1.schema.json new file mode 100644 index 000000000..47547ab08 --- /dev/null +++ b/openapi3/testdata/refInRefInProperty/common-data-objects/problem-details-0.0.1.schema.json @@ -0,0 +1,93 @@ +{ + "title": "Problem details", + "description": "Common data object for describing an error details", + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "title", + "status" + ], + "properties": { + "type": { + "type": "string", + "description": "Unique error code", + "minLength": 1, + "example": "unauthorized", + "x-docs-examples": [ + "validation-error", + "unauthorized", + "forbidden", + "internal-server-error", + "wrong-basket", + "not-found" + ] + }, + "title": { + "type": "string", + "description": "Human readable error message", + "minLength": 1, + "example": "Your request parameters didn't validate", + "x-docs-examples": [ + "Your request parameters didn't validate", + "Requested resource is not available", + "Internal server error" + ] + }, + "status": { + "type": "integer", + "description": "HTTP status code", + "maximum": 599, + "minimum": 100, + "example": 200, + "x-docs-examples": [ + "200", + "201", + "400", + "503" + ] + }, + "detail": { + "type": "string", + "description": "Human readable error description. Only for human", + "example": "Basket must have more then 1 item", + "x-docs-examples": [ + "Basket must have more then 1 item" + ] + }, + "invalid-params": { + "type": "array", + "description": "Param list with errors", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "reason" + ], + "properties": { + "name": { + "type": "string", + "description": "field name", + "minLength": 1, + "example": "age", + "x-docs-examples": [ + "age", + "color" + ] + }, + "reason": { + "type": "string", + "description": "Field validation error text", + "minLength": 1, + "example": "must be a positive integer", + "x-docs-examples": [ + "must be a positive integer", + "must be 'green', 'red' or 'blue'" + ] + } + } + } + } + } +} diff --git a/openapi3/testdata/refInRefInProperty/components/errors.yaml b/openapi3/testdata/refInRefInProperty/components/errors.yaml new file mode 100644 index 000000000..1dc8fa7e3 --- /dev/null +++ b/openapi3/testdata/refInRefInProperty/components/errors.yaml @@ -0,0 +1,66 @@ +components: + schemas: + Error: + type: object + description: Error info in problem-details-0.0.1 format + properties: + error: + $ref: "../common-data-objects/problem-details-0.0.1.schema.json" + + responses: + 400: + description: "" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + json: + $ref: "#/components/examples/BadRequest" + 401: + description: "" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + json: + $ref: "#/components/examples/Unauthorized" + 500: + description: "" + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + examples: + json: + $ref: "#/components/examples/InternalServerError" + + examples: + BadRequest: + summary: Wrong format + value: + error: + type: validation-error + title: Your request parameters didn't validate. + status: 400 + invalid-params: + - name: age + reason: must be a positive integer + - name: color + reason: must be 'green', 'red' or 'blue' + Unauthorized: + summary: Not authenticated + value: + error: + type: unauthorized + title: The request has not been applied because it lacks valid authentication credentials + for the target resource. + status: 401 + InternalServerError: + summary: Not handled internal server error + value: + error: + type: internal-server-error + title: Internal server error. + status: 500 diff --git a/openapi3/testdata/refInRefInProperty/openapi.yaml b/openapi3/testdata/refInRefInProperty/openapi.yaml new file mode 100644 index 000000000..d44b21687 --- /dev/null +++ b/openapi3/testdata/refInRefInProperty/openapi.yaml @@ -0,0 +1,29 @@ +openapi: 3.0.3 + +info: + title: "Reference in reference in property example" + version: "1.0.0" +paths: + /api/test/ref/in/ref/in/property: + post: + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: array + items: + type: string + format: binary + required: true + responses: + 200: + description: "Files are saved successfully" + 400: + $ref: "./components/errors.yaml#/components/responses/400" + 401: + $ref: "./components/errors.yaml#/components/responses/401" + 500: + $ref: "./components/errors.yaml#/components/responses/500"