Repository: swagger-api/swagger-parser
Pull request #885 (2018-10-16 16:58:01)

Fix for issue 884
Hi team,

This PR is to solve the issue #884 (Links Internal Ref Not Resolved).

Please review the PR and merge the same.

Thanks,
Mohammed Rizwan


Patch:
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
index 4f477814..18f0b0aa 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/ResolverFully.java
@@ -5,6 +5,7 @@ import io.swagger.v3.oas.models.Operation;
 import io.swagger.v3.oas.models.PathItem;
 import io.swagger.v3.oas.models.callbacks.Callback;
 import io.swagger.v3.oas.models.examples.Example;
+import io.swagger.v3.oas.models.links.Link;
 import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.ComposedSchema;
 import io.swagger.v3.oas.models.media.MediaType;
@@ -13,6 +14,7 @@ import io.swagger.v3.oas.models.media.Schema;
 import io.swagger.v3.oas.models.parameters.Parameter;
 import io.swagger.v3.oas.models.parameters.RequestBody;
 import io.swagger.v3.oas.models.responses.ApiResponse;
+import io.swagger.v3.oas.models.responses.ApiResponses;
 import io.swagger.v3.parser.models.RefFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,7 +50,7 @@ public class ResolverFully {
     private Map<String, Schema> resolvedModels = new HashMap<>();
     private Map<String, Example> examples;
     private Map<String, RequestBody> requestBodies;
-
+    private Map<String, Link> links;
 
     public void resolveFully(OpenAPI openAPI) {
         if (openAPI.getComponents() != null && openAPI.getComponents().getRequestBodies() != null) {
@@ -72,6 +74,13 @@ public class ResolverFully {
             }
         }
 
+        if (openAPI.getComponents() != null && openAPI.getComponents().getLinks() != null) {
+            links = openAPI.getComponents().getLinks();
+            if (links == null) {
+                links = new HashMap<>();
+            }
+        }
+
         if(openAPI.getPaths() != null) {
             for (String pathname : openAPI.getPaths().keySet()) {
                 PathItem pathItem = openAPI.getPaths().get(pathname);
@@ -138,9 +147,10 @@ public class ResolverFully {
                 }
             }
             // responses
-            if(op.getResponses() != null) {
-                for(String code : op.getResponses().keySet()) {
-                    ApiResponse response = op.getResponses().get(code);
+            ApiResponses responses = op.getResponses();
+            if(responses != null) {
+                for(String code : responses.keySet()) {
+                    ApiResponse response = responses.get(code);
                     if (response.getContent() != null) {
                         Map<String, MediaType> content = response.getContent();
                         for(String mediaType: content.keySet()){
@@ -155,11 +165,31 @@ public class ResolverFully {
                             }
                         }
                     }
+                    Map<String, Link> links = response.getLinks();
+                    if (links != null) {
+                        for (Map.Entry<String, Link> link : links.entrySet()) {
+                            Link value = link.getValue();
+                            Link resolvedValue = value.get$ref() != null ? resolveLink(value) : value;
+                            link.setValue(resolvedValue);
+                        }
+                    }
                 }
             }
         }
     }
 
+    public Link resolveLink(Link link){
+        RefFormat refFormat = computeRefFormat(link.get$ref());
+        String $ref = link.get$ref();
+        if (!isAnExternalRefFormat(refFormat)){
+            if (links != null && !links.isEmpty()) {
+                String referenceKey = computeDefinitionName($ref);
+                return links.getOrDefault(referenceKey, link);
+            }
+        }
+        return link;
+    }
+
     public RequestBody resolveRequestBody(RequestBody requestBody){
         RefFormat refFormat = computeRefFormat(requestBody.get$ref());
         String $ref = requestBody.get$ref();


Test patch:
diff --git a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
index 85e1c915..07855c12 100644
--- a/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
+++ b/modules/swagger-parser-v3/src/test/java/io/swagger/v3/parser/test/OpenAPIV3ParserTest.java
@@ -1538,6 +1538,15 @@ public class OpenAPIV3ParserTest {
         assertEquals(actualPathContent, actualComponentContent);
     }
 
+    @Test
+    public void testIssue884() {
+        ParseOptions parseOptions = new ParseOptions();
+        parseOptions.setResolveFully(true);
+        OpenAPI openAPI = new OpenAPIV3Parser().read("src/test/resources/issue_884.yaml", null, parseOptions);
+        Map<String, Link> links = openAPI.getPaths().get("/2.0/repositories/{username}").getGet().getResponses().get("200").getLinks();
+        String operationId = links.get("userRepository").getOperationId();
+        assertEquals(operationId, "getRepository");
+    }
     @Test
     public void testLinkIssue() {
         ParseOptions parseOptions = new ParseOptions();
@@ -1549,6 +1558,7 @@ public class OpenAPIV3ParserTest {
     }
 
 
+
     private static int getDynamicPort() {
         return new Random().ints(10000, 20000).findFirst().getAsInt();
     }
diff --git a/modules/swagger-parser-v3/src/test/resources/issue_884.yaml b/modules/swagger-parser-v3/src/test/resources/issue_884.yaml
new file mode 100644
index 00000000..fc72545d
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue_884.yaml
@@ -0,0 +1,78 @@
+openapi: 3.0.0
+info:
+  title: Link Example
+  version: 1.0.0
+paths:
+  /2.0/repositories/{username}:
+    get:
+      operationId: getRepositoriesByOwner
+      parameters:
+      - name: username
+        in: path
+        required: true
+        schema:
+          type: string
+      responses:
+        '200':
+          description: repositories owned by the supplied user
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/repository'
+          links:
+            userRepository:
+              $ref: '#/components/links/userRepository'
+  /2.0/repositories/{username}/{slug}:
+    get:
+      operationId: getRepository
+      parameters:
+      - name: username
+        in: path
+        required: true
+        schema:
+          type: string
+      - name: slug
+        in: path
+        required: true
+        schema:
+          type: string
+      responses:
+        '200':
+          description: The repository
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/repository'
+components:
+  links:
+    userRepository:
+      operationId: getRepository
+      requestBody: '$response.body#/slug'
+  schemas:
+    user:
+      type: object
+      properties:
+        username:
+          type: string
+        uuid:
+          type: string
+    repository:
+      type: object
+      properties:
+        slug:
+          type: string
+        owner:
+          $ref: '#/components/schemas/user'
+    pullrequest:
+      type: object
+      properties:
+        id:
+          type: integer
+        title:
+          type: string
+        repository:
+          $ref: '#/components/schemas/repository'
+        author:
+          $ref: '#/components/schemas/user'
\ No newline at end of file