Repository: getkin/kin-openapi
Pull request #178 (2020-02-19 16:23:42)

resolve link refs found in responses.


Patch:
diff --git a/openapi3/swagger_loader.go b/openapi3/swagger_loader.go
index 1a5fda1..84521d4 100644
--- a/openapi3/swagger_loader.go
+++ b/openapi3/swagger_loader.go
@@ -535,6 +535,11 @@ func (swaggerLoader *SwaggerLoader) resolveResponseRef(swagger *Swagger, compone
 			contentType.Schema = schema
 		}
 	}
+	for _, link := range value.Links {
+		if err := swaggerLoader.resolveLinkRef(swagger, link, refDocumentPath); err != nil {
+			return err
+		}
+	}
 	return nil
 }
 
@@ -705,6 +710,45 @@ func (swaggerLoader *SwaggerLoader) resolveExampleRef(swagger *Swagger, componen
 	return nil
 }
 
+func (swaggerLoader *SwaggerLoader) resolveLinkRef(swagger *Swagger, component *LinkRef, path *url.URL) error {
+	// Prevent infinite recursion
+	visited := swaggerLoader.visited
+	if _, isVisited := visited[component]; isVisited {
+		return nil
+	}
+	visited[component] = struct{}{}
+
+	const prefix = "#/components/links/"
+	if ref := component.Ref; len(ref) > 0 {
+		if isSingleRefElement(ref) {
+			var link Link
+			if err := swaggerLoader.loadSingleElementFromURI(ref, path, &link); err != nil {
+				return err
+			}
+
+			component.Value = &link
+		} else {
+			components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path)
+			if err != nil {
+				return err
+			}
+			definitions := components.Links
+			if definitions == nil {
+				return failedToResolveRefFragmentPart(ref, "links")
+			}
+			resolved := definitions[id]
+			if resolved == nil {
+				return failedToResolveRefFragmentPart(ref, id)
+			}
+			if err := swaggerLoader.resolveLinkRef(swagger, resolved, componentPath); err != nil {
+				return err
+			}
+			component.Value = resolved.Value
+		}
+	}
+	return nil
+}
+
 func (swaggerLoader *SwaggerLoader) resolvePathItemRef(swagger *Swagger, entrypoint string, pathItem *PathItem, documentPath *url.URL) (err error) {
 	// Prevent infinite recursion
 	visited := swaggerLoader.visitedFiles


Test patch:
diff --git a/openapi3/swagger_loader_test.go b/openapi3/swagger_loader_test.go
index b5d1194..62b0c48 100644
--- a/openapi3/swagger_loader_test.go
+++ b/openapi3/swagger_loader_test.go
@@ -443,3 +443,48 @@ func TestLoadYamlFileWithExternalPathRef(t *testing.T) {
 	require.NotNil(t, swagger.Paths["/test"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Type)
 	require.Equal(t, "string", swagger.Paths["/test"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Type)
 }
+
+func TestResolveResponseLinkRef(t *testing.T) {
+	source := []byte(`
+openapi: 3.0.1
+info:
+  title: My API
+  version: 1.0.0
+components:
+  links:
+    Father:
+        description: link to to the father
+        operationId: getUserById
+        parameters:
+          "id": "$response.body#/fatherId"
+paths:
+  /users/{id}:
+    get:
+      operationId: getUserById,
+      parameters:
+        - name: id,
+          in: path
+          schema:
+            type: string
+      responses:
+        200:
+          description: A test response
+          content:
+            application/json:
+          links:
+            father:
+              $ref: '#/components/links/Father'
+`)
+	loader := openapi3.NewSwaggerLoader()
+	doc, err := loader.LoadSwaggerFromData(source)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	response := doc.Paths[`/users/{id}`].Get.Responses.Get(200).Value
+	link := response.Links[`father`].Value
+	require.NotNil(t, link)
+	require.Equal(t, "getUserById", link.OperationID)
+	require.Equal(t, "link to to the father", link.Description)
+}