Repository: swagger-api/swagger-parser
Pull request #1320 (2020-02-14 10:18:59)

Fix for issue 1319
Path parameter required value must be true


Patch:
diff --git a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java
index ff0d626a..c70102fd 100644
--- a/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java
+++ b/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java
@@ -110,11 +110,11 @@ public class OpenAPIDeserializer {
     public SwaggerParseResult deserialize(JsonNode rootNode) {
     	return deserialize(rootNode, null);
     }
-    
+
     public SwaggerParseResult deserialize(JsonNode rootNode, String path) {
         SwaggerParseResult result = new SwaggerParseResult();
         try {
-            
+
             ParseResult rootParse = new ParseResult();
             OpenAPI api = parseRoot(rootNode, rootParse, path);
             result.setOpenAPI(api);
@@ -389,7 +389,7 @@ public class OpenAPIDeserializer {
         }
         return servers;
     }
-    
+
     public List<Server> getServersList(ArrayNode obj, String location, ParseResult result) {
 		return getServersList(obj, location, result, null);
 	}
@@ -454,7 +454,7 @@ public class OpenAPIDeserializer {
 
         return server;
     }
-    
+
     boolean isValidURL(String urlString){
 		try {
 			URL url = new URL(urlString);
@@ -560,6 +560,11 @@ public class OpenAPIDeserializer {
                                 if (!definedInPathLevel) {
                                     List<Operation> operationsInAPath = getAllOperationsInAPath(pathObj);
                                     operationsInAPath.forEach(operation -> {
+                                        operation.getParameters().forEach(parameter -> {
+                                            if(PATH_PARAMETER.equalsIgnoreCase(parameter.getIn()) && Boolean.FALSE.equals(parameter.getRequired())){
+                                                result.warning(location, "For path parameter "+ parameter.getName() + " the required value should be true");
+                                            }
+                                        });
                                         if (!isPathParamDefined(pathParam, operation.getParameters())) {
                                             result.warning(location + ".'" + pathName + "'"," Declared path parameter " + pathParam + " needs to be defined as a path parameter in path or operation level");
                                             return;
@@ -1408,6 +1413,9 @@ public class OpenAPIDeserializer {
                 if(parameterObj != null) {
                      parameter = getParameter(parameterObj, String.format("%s.%s", location, parameterName), result);
                     if (parameter != null) {
+                        if(PATH_PARAMETER.equalsIgnoreCase(parameter.getIn()) && Boolean.FALSE.equals(parameter.getRequired())){
+                            result.warning(location, "For path parameter "+ parameterName + " the required value should be true");
+                        }
                         parameters.put(parameterName, parameter);
                     }
                 }
@@ -1448,7 +1456,7 @@ public class OpenAPIDeserializer {
         });
         return parameters;
     }
-    
+
     private Parameter getParameterDefinition(Parameter parameter) {
         if (parameter.get$ref() == null) {
             return parameter;
@@ -1458,7 +1466,7 @@ public class OpenAPIDeserializer {
             .map(Components::getParameters)
             .map(parameters -> parameters.get(parameterSchemaName))
             .orElse(parameter);
-            
+
     }
 
     public Parameter getParameter(ObjectNode obj, String location, ParseResult result) {
@@ -1562,7 +1570,7 @@ public class OpenAPIDeserializer {
         } else {
             parameter.setExplode(Boolean.FALSE);
         }
-        
+
 
         ObjectNode parameterObject = getObject("schema",obj,false,location,result);
         if (parameterObject!= null) {
@@ -1811,7 +1819,7 @@ public class OpenAPIDeserializer {
 
         boolean descriptionRequired, bearerFormatRequired, nameRequired, inRequired, schemeRequired, flowsRequired, openIdConnectRequired;
         descriptionRequired = bearerFormatRequired = nameRequired = inRequired = schemeRequired = flowsRequired = openIdConnectRequired = false;
-        
+
         String value = getString("type", node, true, location, result);
         if (StringUtils.isNotBlank(value)) {
             if (SecurityScheme.Type.APIKEY.toString().equals(value)) {
@@ -1949,7 +1957,7 @@ public class OpenAPIDeserializer {
             authorizationUrlRequired = tokenUrlRequired=true;
             break;
         }
-        
+
         String value = getString("authorizationUrl", node, authorizationUrlRequired, location, result);
         if (StringUtils.isNotBlank(value)) {
             oAuthFlow.setAuthorizationUrl(value);
@@ -2446,7 +2454,7 @@ public class OpenAPIDeserializer {
      * Throws a ParseException if no applicable object can be recognized.
      */
     private Object getDecodedObject( Schema schema, String objectString) throws ParseException {
-        Object object = 
+        Object object =
             objectString == null?
             null :
 
@@ -2483,7 +2491,7 @@ public class OpenAPIDeserializer {
 
         return dateTime;
     }
-    
+
 
   /**
    * Returns the Date represented by the given RFC3339 full-date string.
@@ -2511,7 +2519,7 @@ public class OpenAPIDeserializer {
 
         return date;
     }
-    
+
 
   /**
    * Returns the byte array represented by the given base64-encoded string.
@@ -2519,7 +2527,7 @@ public class OpenAPIDeserializer {
    */
     private byte[] toBytes( String byteString) {
         byte[] bytes;
-        
+
         try {
             bytes = Base64.getDecoder().decode( byteString);
         }
@@ -3050,11 +3058,11 @@ public class OpenAPIDeserializer {
         public void missing(String location, String key) {
             missing.add(new Location(location, key));
         }
-      
+
         public void warning(String location, String key) {
             warnings.add(new Location(location, key));
         }
-      
+
         public void unique(String location, String key) {
             unique.add(new Location(location, key));
 


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 b0db8ada..b401e3df 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
@@ -1826,7 +1826,17 @@ public class OpenAPIV3ParserTest {
     public void checkAllOfAreTaken() {
         OpenAPI openAPI = new OpenAPIV3Parser().read("src/test/resources/allOf-example/allOf.yaml");
         assertEquals(2, openAPI.getComponents().getSchemas().size());
+    }
 
+    @Test
+    public void checkPathParameterRequiredValue() {
+        ParseOptions options = new ParseOptions();
+        options.setResolve(true);
+        SwaggerParseResult swaggerParseResult = new OpenAPIV3Parser().readLocation("src/test/resources/issue-1319.yaml", null, options);
+        assertEquals(2, swaggerParseResult.getMessages().size());
+        assertEquals(2, swaggerParseResult.getOpenAPI().getComponents().getSchemas().size());
+        assertEquals(2, swaggerParseResult.getOpenAPI().getPaths().size());
+        assertEquals(1, swaggerParseResult.getOpenAPI().getComponents().getParameters().size());
     }
 
     @Test(description = "Issue #616 Relative references inside of 'allOf'")
diff --git a/modules/swagger-parser-v3/src/test/resources/issue-1319.yaml b/modules/swagger-parser-v3/src/test/resources/issue-1319.yaml
new file mode 100644
index 00000000..fa95995a
--- /dev/null
+++ b/modules/swagger-parser-v3/src/test/resources/issue-1319.yaml
@@ -0,0 +1,61 @@
+openapi: 3.0.0
+info:
+  description: issue2137
+  version: 1.0.1
+  title: issue2137
+paths:
+  '/users/{user_id}/description':
+    get:
+      operationId: description
+      parameters:
+        - $ref: '#/components/parameters/UserId'
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/goraUrl'
+  '/gora/{gora_id}/test':
+    get:
+      operationId: test
+      parameters:
+        - name: gora_id
+          description: issue-2137
+          in: path
+          required: false
+          schema:
+            type: string
+      responses:
+        '200':
+          description: OK
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/goraUrl'
+components:
+  parameters:
+    UserId:
+      name: user_id
+      description: Unique identifier of a user
+      in: path
+      required: false
+      schema:
+        type: string
+  schemas:
+    gora:
+      type: object
+      description: Information about de product
+      properties:
+        text:
+          type: string
+    goraUrl:
+      allOf:
+        - type: object
+          required:
+            - url
+          properties:
+            url:
+              type: string
+              description: Url with information or picture of the product
+        - $ref: '#/components/schemas/gora'
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/OpenAPIParserTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/OpenAPIParserTest.java
index 3ea1ab11..7f14b579 100644
--- a/modules/swagger-parser/src/test/java/io/swagger/parser/OpenAPIParserTest.java
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/OpenAPIParserTest.java
@@ -83,7 +83,7 @@ public class OpenAPIParserTest {
         System.out.println(result.getMessages());
         assertNotNull(result);
         assertNotNull(result.getOpenAPI());
-        assertEquals(result.getMessages().get(0), "attribute tags.sample is repeated");
+        assertEquals(result.getMessages().get(1), "attribute tags.sample is repeated");
     }
 
     @Test