Repository: swagger-api/swagger-parser
Pull request #1358 (2020-04-23 11:14:44)

gh-505: Fix relative paths in parameters, examples and links
Fix Unable to load RELATIVE ref for parameters, examples and links.
@gracekarina


Link: #505


Patch:
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java
index 617f6bea..0dd95535 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java
@@ -1,6 +1,13 @@
 package io.swagger.v3.parser.processors;
 
 
+import java.net.URI;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
 import io.swagger.v3.oas.models.Components;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Operation;
@@ -13,28 +20,17 @@ import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.ComposedSchema;
 import io.swagger.v3.oas.models.media.Discriminator;
 import io.swagger.v3.oas.models.media.MediaType;
-import io.swagger.v3.oas.models.media.ObjectSchema;
 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.oas.models.security.SecurityScheme;
 import io.swagger.v3.parser.ResolverCache;
 import io.swagger.v3.parser.models.RefFormat;
 import io.swagger.v3.parser.models.RefType;
-import io.swagger.v3.parser.util.RefUtils;
-
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.LoggerFactory;
 
-import java.net.URI;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
 import static io.swagger.v3.parser.util.RefUtils.computeDefinitionName;
 import static io.swagger.v3.parser.util.RefUtils.computeRefFormat;
 import static io.swagger.v3.parser.util.RefUtils.getExternalPath;
@@ -280,17 +276,24 @@ public final class ExternalRefProcessor {
                                                 if (schema != null) {
                                                     processRefSchemaObject(mediaType.getSchema(), $ref);
                                                 }
+                                                if (mediaType.getExamples() != null) {
+                                                    processRefExamples(mediaType.getExamples(), $ref);
+                                                }
+
                                             }
                                         }
                                     }
+                                    if (response.getLinks() != null) {
+                                        processRefLinks(response.getLinks(), $ref);
+                                    }
                                 }
                             }
                         }
                     }
                     if (operation.getRequestBody() != null) {
                         RequestBody body = operation.getRequestBody();
-                        Schema schema = null;
                         if (body.getContent() != null) {
+                            Schema schema;
                             Map<String, MediaType> content = body.getContent();
                             for (String mediaName : content.keySet()) {
                                 MediaType mediaType = content.get(mediaName);
@@ -303,6 +306,13 @@ public final class ExternalRefProcessor {
                             }
                         }
                     }
+
+                    final List<Parameter> parameters = operation.getParameters();
+                    if (parameters != null) {
+                        parameters.stream()
+                            .filter(parameter -> parameter.getSchema() != null)
+                            .forEach(parameter -> this.processRefSchemaObject(parameter.getSchema(), $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 c1dee094..6d593127 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
@@ -1,6 +1,19 @@
 package io.swagger.v3.parser.test;
 
 
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.github.tomakehurst.wiremock.WireMockServer;
@@ -11,17 +24,19 @@ import io.swagger.v3.core.util.Yaml;
 import io.swagger.v3.oas.models.Components;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.Operation;
-import io.swagger.v3.oas.models.Paths;
 import io.swagger.v3.oas.models.PathItem;
+import io.swagger.v3.oas.models.Paths;
+import io.swagger.v3.oas.models.examples.Example;
 import io.swagger.v3.oas.models.headers.Header;
 import io.swagger.v3.oas.models.links.Link;
-import io.swagger.v3.oas.models.media.*;
-import io.swagger.v3.oas.models.examples.Example;
 import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.ByteArraySchema;
 import io.swagger.v3.oas.models.media.ComposedSchema;
 import io.swagger.v3.oas.models.media.Content;
 import io.swagger.v3.oas.models.media.IntegerSchema;
+import io.swagger.v3.oas.models.media.MapSchema;
+import io.swagger.v3.oas.models.media.MediaType;
+import io.swagger.v3.oas.models.media.ObjectSchema;
 import io.swagger.v3.oas.models.media.Schema;
 import io.swagger.v3.oas.models.media.StringSchema;
 import io.swagger.v3.oas.models.parameters.HeaderParameter;
@@ -45,21 +60,22 @@ import org.testng.annotations.BeforeClass;
 import org.testng.annotations.Test;
 import org.testng.reporters.Files;
 
-import java.io.File;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.net.HttpURLConnection;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.*;
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathMatching;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.junit.Assert.assertThat;
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 
 public class OpenAPIV3ParserTest {
@@ -147,6 +163,21 @@ public class OpenAPIV3ParserTest {
         assertNotNull(openAPI.getComponents().getSchemas().get("Error"));
     }
 
+    @Test
+    public void testIssue_505() {
+        OpenAPIV3Parser openApiParser = new OpenAPIV3Parser();
+        ParseOptions options = new ParseOptions();
+        options.setResolve(true);
+        SwaggerParseResult parseResult = openApiParser.readLocation("issue-505/petstore.yml", null, options);
+        OpenAPI openAPI = parseResult.getOpenAPI();
+
+        assertNotNull(openAPI.getComponents().getSchemas().get("DateWithExample"));
+        assertNotNull(openAPI.getComponents().getExamples().get("DateWithExample"));
+        assertNotNull(openAPI.getComponents().getLinks().get("userRepository"));
+
+        assertEquals(3, openAPI.getPaths().get("/pets").getGet().getParameters().size());
+    }
+
     @Test
     public void testFlattenComposedSchema() {
         OpenAPIV3Parser openApiParser = new OpenAPIV3Parser();
diff --git a/modules/swagger-parser-v3/src/test/resources/issue-505/pets/def.yml b/modules/swagger-parser-v3/src/test/resources/issue-505/pets/def.yml
new file mode 100644
index 00000000..6234851d
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue-505/pets/def.yml
@@ -0,0 +1,40 @@
+components:
+  schemas:
+    Pet:
+      type: object
+      required:
+        - id
+        - name
+      properties:
+        id:
+          type: integer
+          format: int64
+        name:
+          type: string
+        tag:
+          type: string
+    Pets:
+      type: array
+      items:
+        $ref: "#/components/schemas/Pet"
+    Error:
+      type: object
+      required:
+        - code
+        - message
+      properties:
+        code:
+          type: integer
+          format: int32
+        message:
+          type: string
+
+  links:
+    userRepository:
+      operationId: getRepository
+      requestBody: '$response.body#/slug'
+      headers:
+        X-Rate-Limit:
+          description: The number of allowed requests in the current period
+          schema:
+            type: integer
\ No newline at end of file
diff --git a/modules/swagger-parser-v3/src/test/resources/issue-505/pets/pets.yml b/modules/swagger-parser-v3/src/test/resources/issue-505/pets/pets.yml
new file mode 100644
index 00000000..808c45ff
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue-505/pets/pets.yml
@@ -0,0 +1,71 @@
+get:
+  summary: List all pets
+  operationId: listPets
+  tags:
+    - pets
+  parameters:
+    - name: myParam
+      in: query
+      description: Param
+      required: true
+      schema:
+        $ref: 'def.yml#/components/schemas/Pet'
+    - name: myParam2
+      in: query
+      description: Param2
+      required: true
+      schema:
+        $ref: './def.yml#/components/schemas/Pet'
+    - name: myParam3
+      in: query
+      description: Param3
+      required: true
+      schema:
+        $ref: '../pets/def.yml#/components/schemas/Pet'
+  responses:
+    "200":
+      description: A paged array of pets
+      headers:
+        x-next:
+          description: A link to the next page of responses
+          schema:
+            type: string
+      content:
+        application/json:
+          schema:
+            $ref: "./def.yml#/components/schemas/Pets"
+    default:
+      description: unexpected error
+      content:
+        application/json:
+          schema:
+            $ref: "./def.yml#/components/schemas/Error"
+post:
+  summary: Create a pet
+  operationId: createPets
+  tags:
+    - pets
+  responses:
+    '201':
+      description: New guest added to event list
+      content:
+        application/json:
+          schema:
+            properties:
+              test:
+                type: string
+          examples:
+            testExamples:
+              $ref: "../petstore.yml#/components/schemas/DateWithExample"
+      links:
+        userRepository:
+          $ref: 'def.yml#/components/links/userRepository'
+    default:
+      description: unexpected error
+      content:
+        application/json:
+          schema:
+            $ref: "./def.yml#/components/schemas/Error"
+          example:
+            $ref: "../petstore.yml#/components/schemas/DateWithExample"
+
diff --git a/modules/swagger-parser-v3/src/test/resources/issue-505/petstore.yml b/modules/swagger-parser-v3/src/test/resources/issue-505/petstore.yml
new file mode 100644
index 00000000..ea298975
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue-505/petstore.yml
@@ -0,0 +1,21 @@
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: Swagger Petstore
+  license:
+    name: MIT
+servers:
+  - url: http://petstore.swagger.io/v1
+paths:
+  /pets:
+    $ref: "./pets/pets.yml"
+
+components:
+  schemas:
+    Date:
+      type: string
+      format: date
+    DateWithExample:
+      $ref: '#/components/schemas/Date'
+      description: Date schema extended with a `default` value... Or not?
+      default: 2000-01-01