From f9a16d856ce28f61b8c3ea89a5451f6441f7fcc0 Mon Sep 17 00:00:00 2001 From: Camille Chafer Date: Wed, 25 Feb 2015 16:23:58 +0100 Subject: [PATCH] Add 'default' response (200) to responses list, and add Types to the CodegenResponse object (#293). In the same time, clarify, simplfy and factorize code. --- .../swagger/codegen/DefaultCodegen.java | 111 ++++++-------- .../resources/2_0/responseSelectionTest.json | 139 ++++++++++++++++++ .../src/test/scala/CodegenTest.scala | 27 ++++ 3 files changed, 214 insertions(+), 63 deletions(-) create mode 100644 modules/swagger-codegen/src/test/resources/2_0/responseSelectionTest.json diff --git a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java index e971eff343f..7b600ff488d 100644 --- a/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java +++ b/modules/swagger-codegen/src/main/java/com/wordnik/swagger/codegen/DefaultCodegen.java @@ -142,6 +142,8 @@ public class DefaultCodegen { return name; } + public String toOperationId(String operationId) { return operationId; } + public String toVarName(String name) { if(reservedWords.contains(name)) return escapeReservedWord(name); @@ -156,6 +158,7 @@ public class DefaultCodegen { return name; } + public String escapeReservedWord(String name) { throw new RuntimeException("reserved word " + name + " not allowed"); } @@ -537,6 +540,20 @@ public class DefaultCodegen { return property; } + private Response findMethodResponse(Map responses) { + String code = null; + for(String responseCode : responses.keySet()) { + if (responseCode.startsWith("2") || responseCode.equals("default")) { + if (code == null || code.compareTo(responseCode) > 0) { + code = responseCode; + } + } + } + if (code == null) + return null; + return responses.get(code); + } + public CodegenOperation fromOperation(String path, String httpMethod, Operation operation){ CodegenOperation op = CodegenModelFactory.newInstance(CodegenModelType.OPERATION); Set imports = new HashSet(); @@ -566,13 +583,11 @@ public class DefaultCodegen { LOGGER.warn("generated operationId " + operationId); } op.path = path; - op.operationId = operationId; + op.operationId = toOperationId(operationId); op.summary = escapeText(operation.getSummary()); op.notes = escapeText(operation.getDescription()); op.tags = operation.getTags(); - Response methodResponse = null; - if(operation.getConsumes() != null && operation.getConsumes().size() > 0) { List> c = new ArrayList>(); int count = 0; @@ -603,69 +618,39 @@ public class DefaultCodegen { op.hasProduces = true; } - if(operation.getResponses() != null) { - for(String responseCode: new TreeSet(operation.getResponses().keySet())) { - Response response = operation.getResponses().get(responseCode); - if (responseCode.startsWith("2")) { - // use the first, i.e. the smallest 2xx response status as methodResponse - methodResponse = response; - break; + if (operation.getResponses() != null && !operation.getResponses().isEmpty()) { + + Response methodResponse = findMethodResponse(operation.getResponses()); + CodegenResponse methodCodegenResponse = null; + + for (Map.Entry entry : operation.getResponses().entrySet()) { + Response response = entry.getValue(); + CodegenResponse r = fromResponse(entry.getKey(), response); + r.hasMore = true; + if (response == methodResponse) + methodCodegenResponse = r; + op.responses.add(r); + } + op.responses.get(op.responses.size() - 1).hasMore = false; + + if (methodResponse != null) { + op.returnType = methodCodegenResponse.dataType; + op.returnBaseType = methodCodegenResponse.baseType; + op.returnSimpleType = methodCodegenResponse.simpleType; + op.returnTypeIsPrimitive = methodCodegenResponse.primitiveType; + op.returnContainer = methodCodegenResponse.containerType; + op.isListContainer = methodCodegenResponse.isListContainer; + op.isMapContainer = methodCodegenResponse.isMapContainer; + if (methodResponse.getSchema() != null) { + Property responseProperty = methodResponse.getSchema(); + responseProperty.setRequired(true); + CodegenProperty cm = fromProperty("response", responseProperty); + op.examples = toExamples(methodResponse.getExamples()); + op.defaultResponse = toDefaultValue(responseProperty); + addHeaders(methodResponse, op.responseHeaders); } - } - if(methodResponse == null && operation.getResponses().keySet().contains("default")) { - methodResponse = operation.getResponses().get("default"); - } - for(String responseCode: operation.getResponses().keySet()) { - Response response = operation.getResponses().get(responseCode); - if(response != methodResponse) { - CodegenResponse r = fromResponse(responseCode, response); - op.responses.add(r); - } - for(int i = 0; i < op.responses.size() - 1; i++) { - CodegenResponse r = op.responses.get(i); - r.hasMore = new Boolean(true); - } - } - } - if(methodResponse != null) { - if (methodResponse.getSchema() != null) { - CodegenProperty cm = fromProperty("response", methodResponse.getSchema()); - - Property responseProperty = methodResponse.getSchema(); - - if(responseProperty instanceof ArrayProperty) { - ArrayProperty ap = (ArrayProperty) responseProperty; - CodegenProperty innerProperty = fromProperty("response", ap.getItems()); - op.returnBaseType = innerProperty.baseType; } - else { - if(cm.complexType != null) - op.returnBaseType = cm.complexType; - else - op.returnBaseType = cm.baseType; - } - op.examples = toExamples(methodResponse.getExamples()); - op.defaultResponse = toDefaultValue(responseProperty); - op.returnType = cm.datatype; - if(cm.isContainer != null) { - op.returnContainer = cm.containerType; - if("map".equals(cm.containerType)) - op.isMapContainer = Boolean.TRUE; - else if ("list".equalsIgnoreCase(cm.containerType)) - op.isListContainer = Boolean.TRUE; - } - else - op.returnSimpleType = true; - if (languageSpecificPrimitives().contains(op.returnBaseType) || op.returnBaseType == null) - op.returnTypeIsPrimitive = true; - } - addHeaders(methodResponse, op.responseHeaders); - } - - if(op.returnBaseType == null) { - op.returnTypeIsPrimitive = true; - op.returnSimpleType = true; } if(op.returnBaseType != null && diff --git a/modules/swagger-codegen/src/test/resources/2_0/responseSelectionTest.json b/modules/swagger-codegen/src/test/resources/2_0/responseSelectionTest.json new file mode 100644 index 00000000000..f698c96425a --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/2_0/responseSelectionTest.json @@ -0,0 +1,139 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters", + "version": "1.0.0", + "title": "Swagger Petstore", + "termsOfService": "http://helloreverb.com/terms/", + "contact": { + "email": "apiteam@wordnik.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "petstore.swagger.io", + "basePath": "/v2", + "schemes": [ + "http" + ], + "paths": { + "/tests/withTwoHundredAndDefault": { + "get": { + "summary": "Operation with several unordered 2XX results and one default", + "description": "", + "operationId": "withTwoHundredAndDefault", + "produces": [ + "application/json" + ], + "responses": { + "default": { + "description": "default response", + "schema": { + "type": "integer", + "format": "int32" + } + }, + "100": { + "description": "100 response", + "schema": { + "type": "integer", + "format": "int32" + } + }, + "202": { + "description": "201 response", + "schema": { + "type": "integer", + "format": "int64" + } + }, + "203": { + "description": "202 response", + "schema": { + "type": "integer", + "format": "int32" + } + }, + "400": { + "description": "400 response", + "schema": { + "type": "integer", + "format": "int32" + } + }, + "201": { + "description": "200 response", + "schema": { + "type": "string" + } + } + } + } + }, + "/tests/withoutTwoHundredButDefault": { + "get": { + "summary": "Operation with several unordered 2XX results and one default", + "description": "", + "operationId": "withoutTwoHundredButDefault", + "produces": [ + "application/json" + ], + "responses": { + "default": { + "description": "default response", + "schema": { + "type": "string" + } + }, + "100": { + "description": "100 response", + "schema": { + "type": "integer", + "format": "int32" + } + }, + "301": { + "description": "301 response", + "schema": { + "type": "integer", + "format": "int64" + } + } + } + } + } + }, + "securityDefinitions": { + "api_key": { + "type": "apiKey", + "name": "api_key", + "in": "header" + }, + "petstore_auth": { + "type": "oauth2", + "authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog", + "flow": "implicit", + "scopes": { + "write:pets": "modify pets in your account", + "read:pets": "read your pets" + } + } + }, + "definitions": { + "CustomModel": { + "required": ["id"], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string", + "example": "doggie" + } + } + } + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/test/scala/CodegenTest.scala b/modules/swagger-codegen/src/test/scala/CodegenTest.scala index a9ccbd9f0f2..91f0c5dba2c 100644 --- a/modules/swagger-codegen/src/test/scala/CodegenTest.scala +++ b/modules/swagger-codegen/src/test/scala/CodegenTest.scala @@ -94,4 +94,31 @@ class CodegenTest extends FlatSpec with Matchers { statusParam.required should equal (false) statusParam.hasMore should be (null) } + + it should "select main response from a 2.0 spec using the lowest 2XX code" in { + val model = new SwaggerParser() + .read("src/test/resources/2_0/responseSelectionTest.json") + + val codegen = new DefaultCodegen() + + val path = "/tests/withTwoHundredAndDefault" + val p = model.getPaths().get(path).getGet() + val op = codegen.fromOperation(path, "get", p) + op.returnType should be("String") + + } + + it should "select main response from a 2.0 spec using the default keyword when no 2XX code" in { + val model = new SwaggerParser() + .read("src/test/resources/2_0/responseSelectionTest.json") + + val codegen = new DefaultCodegen() + + val path = "/tests/withoutTwoHundredButDefault" + val p = model.getPaths().get(path).getGet() + val op = codegen.fromOperation(path, "get", p) + op.returnType should be("String") + + } + } \ No newline at end of file