From 23fee386f2d4cb3a43710ef8e4138011b8e1fdcc Mon Sep 17 00:00:00 2001 From: raj k Date: Wed, 19 Oct 2016 13:40:16 -0700 Subject: [PATCH] Vendor Mime-type support in retrofit2 --- .../io/swagger/codegen/CodegenOperation.java | 5 +- .../codegen/languages/JavaClientCodegen.java | 90 +- .../Java/libraries/retrofit2/api.mustache | 9 + .../languages/JavaClientCodegenTest.java | 79 ++ .../resources/2_0/petstore-vendor-mime.yaml | 1232 +++++++++++++++++ .../java/io/swagger/client/api/FakeApi.java | 5 +- .../java/io/swagger/client/api/PetApi.java | 8 +- 7 files changed, 1418 insertions(+), 10 deletions(-) create mode 100644 modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/JavaClientCodegenTest.java create mode 100644 modules/swagger-codegen/src/test/resources/2_0/petstore-vendor-mime.yaml diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java index 501479955fd..1bd02c68d5d 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/CodegenOperation.java @@ -19,7 +19,7 @@ public class CodegenOperation { isRestful; public String path, operationId, returnType, httpMethod, returnBaseType, returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse, discriminator; - public List> consumes, produces; + public List> consumes, produces, prioritizedContentTypes; public CodegenParameter bodyParam; public List allParams = new ArrayList(); public List bodyParams = new ArrayList(); @@ -275,6 +275,8 @@ public class CodegenOperation { return false; if (nickname != null ? !nickname.equals(that.nickname) : that.nickname != null) return false; + if ( prioritizedContentTypes != null ? !prioritizedContentTypes.equals(that.prioritizedContentTypes) : that.prioritizedContentTypes != null ) + return false; return operationIdLowerCase != null ? operationIdLowerCase.equals(that.operationIdLowerCase) : that.operationIdLowerCase == null; } @@ -325,6 +327,7 @@ public class CodegenOperation { result = 31 * result + (externalDocs != null ? externalDocs.hashCode() : 0); result = 31 * result + (vendorExtensions != null ? vendorExtensions.hashCode() : 0); result = 31 * result + (nickname != null ? nickname.hashCode() : 0); + result = 31 * result + (prioritizedContentTypes != null ? prioritizedContentTypes.hashCode() : 0); result = 31 * result + (operationIdLowerCase != null ? operationIdLowerCase.hashCode() : 0); return result; } diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java index 58286080a81..776d849f478 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/JavaClientCodegen.java @@ -8,9 +8,12 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.*; +import java.util.regex.Pattern; public class JavaClientCodegen extends AbstractJavaCodegen { - @SuppressWarnings("hiding") + static final String MEDIA_TYPE = "mediaType"; + + @SuppressWarnings("hiding") private static final Logger LOGGER = LoggerFactory.getLogger(JavaClientCodegen.class); public static final String USE_RX_JAVA = "useRxJava"; @@ -173,24 +176,73 @@ public class JavaClientCodegen extends AbstractJavaCodegen { List ops = (List) operations.get("operation"); for (CodegenOperation operation : ops) { if (operation.hasConsumes == Boolean.TRUE) { - Map firstType = operation.consumes.get(0); - if (firstType != null) { - if ("multipart/form-data".equals(firstType.get("mediaType"))) { - operation.isMultipart = Boolean.TRUE; - } + + if ( isMultipartType(operation.consumes) ) { + operation.isMultipart = Boolean.TRUE; + } + else { + operation.prioritizedContentTypes = prioritizeContentTypes(operation.consumes); } } if (operation.returnType == null) { operation.returnType = "Void"; } if (usesRetrofit2Library() && StringUtils.isNotEmpty(operation.path) && operation.path.startsWith("/")) - operation.path = operation.path.substring(1); + operation.path = operation.path.substring(1); } } } return objs; } + /** + * Prioritizes consumes mime-type list by moving json-vendor and json mime-types up front, but + * otherwise preserves original consumes definition order. + * [application/vnd...+json,... application/json, ..as is..] + * + * @param consumes consumes mime-type list + * @return + */ + static List> prioritizeContentTypes(List> consumes) { + if ( consumes.size() <= 1 ) + return consumes; + + List> prioritizedContentTypes = new ArrayList<>(consumes.size()); + + List> jsonVendorMimeTypes = new ArrayList<>(consumes.size()); + List> jsonMimeTypes = new ArrayList<>(consumes.size()); + + for ( Map consume : consumes) { + if ( isJsonVendorMimeType(consume.get(MEDIA_TYPE))) { + jsonVendorMimeTypes.add(consume); + } + else if ( isJsonMimeType(consume.get(MEDIA_TYPE))) { + jsonMimeTypes.add(consume); + } + else + prioritizedContentTypes.add(consume); + + consume.put("hasMore", "true"); + } + + prioritizedContentTypes.addAll(0, jsonMimeTypes); + prioritizedContentTypes.addAll(0, jsonVendorMimeTypes); + + prioritizedContentTypes.get(prioritizedContentTypes.size()-1).put("hasMore", null); + + return prioritizedContentTypes; + } + + private static boolean isMultipartType(List> consumes) { + Map firstType = consumes.get(0); + if (firstType != null) { + if ("multipart/form-data".equals(firstType.get(MEDIA_TYPE))) { + return true; + } + } + return false; + } + @Override public void postProcessModelProperty(CodegenModel model, CodegenProperty property) { super.postProcessModelProperty(model, property); @@ -245,4 +297,28 @@ public class JavaClientCodegen extends AbstractJavaCodegen { this.supportJava6 = value; } + final private static Pattern JSON_MIME_PATTERN = Pattern.compile("(?i)application\\/json(;.*)?"); + final private static Pattern JSON_VENDOR_MIME_PATTERN = Pattern.compile("(?i)application\\/vnd.(.*)+json(;.*)?"); + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + */ + static boolean isJsonMimeType(String mime) { + return mime != null && ( JSON_MIME_PATTERN.matcher(mime).matches()); + } + + /** + * Check if the given MIME is a JSON Vendor MIME. + * JSON MIME examples: + * application/vnd.mycompany+json + * application/vnd.mycompany.resourceA.version1+json + */ + static boolean isJsonVendorMimeType(String mime) { + return mime != null && JSON_VENDOR_MIME_PATTERN.matcher(mime).matches(); + } + } diff --git a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/api.mustache b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/api.mustache index 7682d27c9c8..3b32a240726 100644 --- a/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/api.mustache +++ b/modules/swagger-codegen/src/main/resources/Java/libraries/retrofit2/api.mustache @@ -29,6 +29,15 @@ public interface {{classname}} { */ {{#formParams}}{{#-first}} {{#isMultipart}}@retrofit2.http.Multipart{{/isMultipart}}{{^isMultipart}}@retrofit2.http.FormUrlEncoded{{/isMultipart}}{{/-first}}{{/formParams}} + {{^formParams}} + {{#prioritizedContentTypes}} + {{#-first}} + @Headers({ + "Content-Type:{{mediaType}}" + }) + {{/-first}} + {{/prioritizedContentTypes}} + {{/formParams}} @{{httpMethod}}("{{path}}") {{#useRxJava}}Observable{{/useRxJava}}{{^useRxJava}}Call{{/useRxJava}}<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> {{operationId}}({{^allParams}});{{/allParams}} {{#allParams}}{{>libraries/retrofit2/queryParams}}{{>libraries/retrofit2/pathParams}}{{>libraries/retrofit2/headerParams}}{{>libraries/retrofit2/bodyParams}}{{>libraries/retrofit2/formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} diff --git a/modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/JavaClientCodegenTest.java b/modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/JavaClientCodegenTest.java new file mode 100644 index 00000000000..2dceedacf93 --- /dev/null +++ b/modules/swagger-codegen/src/test/java/io/swagger/codegen/languages/JavaClientCodegenTest.java @@ -0,0 +1,79 @@ +package io.swagger.codegen.languages; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class JavaClientCodegenTest { + + private static final String VENDOR_MIME_TYPE = "application/vnd.company.v1+json"; + private static final String XML_MIME_TYPE = "application/xml"; + private static final String JSON_MIME_TYPE = "application/json"; + private static final String TEXT_MIME_TYPE = "text/plain"; + + @Test + public void testJsonMime() { + Assert.assertTrue(JavaClientCodegen.isJsonMimeType(JSON_MIME_TYPE)); + Assert.assertFalse(JavaClientCodegen.isJsonMimeType(XML_MIME_TYPE)); + Assert.assertFalse(JavaClientCodegen.isJsonMimeType(TEXT_MIME_TYPE)); + + Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany+json")); + Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.v1+json")); + Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.resourceTypeA.version1+json")); + Assert.assertTrue(JavaClientCodegen.isJsonVendorMimeType("application/vnd.mycompany.resourceTypeB.version2+json")); + Assert.assertFalse(JavaClientCodegen.isJsonVendorMimeType("application/v.json")); + + } + + @Test + public void testContentTypePrioritization() { + Map jsonMimeType = new HashMap<>(); + jsonMimeType.put(JavaClientCodegen.MEDIA_TYPE, JSON_MIME_TYPE); + + Map xmlMimeType = new HashMap<>(); + xmlMimeType.put(JavaClientCodegen.MEDIA_TYPE, XML_MIME_TYPE); + + Map vendorMimeType = new HashMap<>(); + vendorMimeType.put(JavaClientCodegen.MEDIA_TYPE, VENDOR_MIME_TYPE); + + Map textMimeType = new HashMap<>(); + textMimeType.put(JavaClientCodegen.MEDIA_TYPE, TEXT_MIME_TYPE); + + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes( + Collections.>emptyList()), Collections.emptyList()); + + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType)), Arrays.asList(xmlMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType)), Arrays.asList(jsonMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(vendorMimeType)), Arrays.asList(vendorMimeType)); + + + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType, jsonMimeType)), + Arrays.asList(jsonMimeType, xmlMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType, xmlMimeType)), + Arrays.asList(jsonMimeType, xmlMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(jsonMimeType, vendorMimeType)), + Arrays.asList(vendorMimeType, jsonMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(textMimeType, xmlMimeType)), + Arrays.asList(textMimeType, xmlMimeType)); + Assert.assertEquals(JavaClientCodegen.prioritizeContentTypes(Arrays.asList(xmlMimeType, textMimeType)), + Arrays.asList(xmlMimeType, textMimeType)); + + System.out.println(JavaClientCodegen.prioritizeContentTypes(Arrays.asList( + xmlMimeType,textMimeType, jsonMimeType, vendorMimeType))); + + List> priContentTypes = JavaClientCodegen.prioritizeContentTypes(Arrays.asList( + xmlMimeType, textMimeType, jsonMimeType, vendorMimeType)); + Assert.assertEquals(priContentTypes, Arrays.asList(vendorMimeType, jsonMimeType, xmlMimeType, textMimeType)); + + for ( int i = 0; i < 3; i++ ) + Assert.assertNotNull(priContentTypes.get(i).get("hasMore")); + Assert.assertNull(priContentTypes.get(3).get("hasMore")); + + } + +} diff --git a/modules/swagger-codegen/src/test/resources/2_0/petstore-vendor-mime.yaml b/modules/swagger-codegen/src/test/resources/2_0/petstore-vendor-mime.yaml new file mode 100644 index 00000000000..57380003800 --- /dev/null +++ b/modules/swagger-codegen/src/test/resources/2_0/petstore-vendor-mime.yaml @@ -0,0 +1,1232 @@ +swagger: '2.0' +info: + description: "This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\" + version: 1.0.0 + title: Swagger Petstore + termsOfService: 'http://swagger.io/terms/' + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: 'http://www.apache.org/licenses/LICENSE-2.0.html' +host: petstore.swagger.io +basePath: /v2 +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: 'http://swagger.io' + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user + externalDocs: + description: Find out more about our store + url: 'http://swagger.io' +schemes: + - http +paths: + /pet: + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + consumes: + - application/vnd.mycompany.resA.v1+json + - application/xml + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Pet object that needs to be added to the store + required: true + schema: + $ref: '#/definitions/Pet' + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + put: + tags: + - pet + summary: Update an existing pet + description: '' + operationId: updatePet + consumes: + - application/vnd.mycompany.v1+json + - application/xml + produces: + - application/json + parameters: + - in: body + name: body + description: Pet object that needs to be added to the store + required: true + schema: + $ref: '#/definitions/Pet' + responses: + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + produces: + - application/xml + - application/json + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + collectionFormat: csv + responses: + '200': + description: successful operation + schema: + type: array + items: + $ref: '#/definitions/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.' + operationId: findPetsByTags + produces: + - application/xml + - application/json + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + type: array + items: + type: string + collectionFormat: csv + responses: + '200': + description: successful operation + schema: + type: array + items: + $ref: '#/definitions/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet/{petId}': + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + type: integer + format: int64 + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + consumes: + - application/x-www-form-urlencoded + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + type: integer + format: int64 + - name: name + in: formData + description: Updated name of the pet + required: false + type: string + - name: status + in: formData + description: Updated status of the pet + required: false + type: string + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + delete: + tags: + - pet + summary: Deletes a pet + description: '' + operationId: deletePet + produces: + - application/xml + - application/json + parameters: + - name: api_key + in: header + required: false + type: string + - name: petId + in: path + description: Pet id to delete + required: true + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet/{petId}/uploadImage': + post: + tags: + - pet + summary: uploads an image + description: '' + operationId: uploadFile + consumes: + - multipart/form-data + produces: + - application/json + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + type: integer + format: int64 + - name: additionalMetadata + in: formData + description: Additional data to pass to server + required: false + type: string + - name: file + in: formData + description: file to upload + required: false + type: file + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + produces: + - application/json + parameters: [] + responses: + '200': + description: successful operation + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: '' + operationId: placeOrder + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: order placed for purchasing the pet + required: true + schema: + $ref: '#/definitions/Order' + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Order' + '400': + description: Invalid Order + '/store/order/{orderId}': + get: + tags: + - store + summary: Find purchase order by ID + description: 'For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions' + operationId: getOrderById + produces: + - application/xml + - application/json + parameters: + - name: orderId + in: path + description: ID of pet that needs to be fetched + required: true + type: integer + maximum: 5 + minimum: 1 + format: int64 + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + operationId: deleteOrder + produces: + - application/xml + - application/json + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + type: string + minimum: 1 + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Created user object + required: true + schema: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: query + description: The user name for login + required: true + type: string + - name: password + in: query + description: The password for login in clear text + required: true + type: string + responses: + '200': + description: successful operation + schema: + type: string + headers: + X-Rate-Limit: + type: integer + format: int32 + description: calls per hour allowed by the user + X-Expires-After: + type: string + format: date-time + description: date in UTC when toekn expires + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + produces: + - application/xml + - application/json + parameters: [] + responses: + default: + description: successful operation + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: 'The name that needs to be fetched. Use user1 for testing. ' + required: true + type: string + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + type: string + - in: body + name: body + description: Updated user object + required: true + schema: + $ref: '#/definitions/User' + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + + /fake: + patch: + tags: + - fake + summary: To test "client" model + descriptions: To test "client" model + operationId: testClientModel + consumes: + - application/json + produces: + - application/json + parameters: + - in: body + name: body + description: client model + required: true + schema: + $ref: '#/definitions/Client' + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Client' + get: + tags: + - fake + summary: To test enum parameters + descriptions: To test enum parameters + operationId: testEnumParameters + consumes: + - application/json + produces: + - application/json + parameters: + - name: enum_form_string_array + type: array + items: + type: string + default: '$' + enum: + - '>' + - '$' + in: formData + description: Form parameter enum test (string array) + - name: enum_form_string + type: string + default: '-efg' + enum: + - _abc + - '-efg' + - (xyz) + in: formData + description: Form parameter enum test (string) + - name: enum_header_string_array + type: array + items: + type: string + default: '$' + enum: + - '>' + - '$' + in: header + description: Header parameter enum test (string array) + - name: enum_header_string + type: string + default: '-efg' + enum: + - _abc + - '-efg' + - (xyz) + in: header + description: Header parameter enum test (string) + - name: enum_query_string_array + type: array + items: + type: string + default: '$' + enum: + - '>' + - '$' + in: query + description: Query parameter enum test (string array) + - name: enum_query_string + type: string + default: '-efg' + enum: + - _abc + - '-efg' + - (xyz) + in: query + description: Query parameter enum test (string) + - name: enum_query_integer + type: number + format: int32 + enum: + - 1 + - -2 + in: query + description: Query parameter enum test (double) + - name: enum_query_double + type: number + format: double + enum: + - 1.1 + - -1.2 + in: formData + description: Query parameter enum test (double) + responses: + '400': + description: Invalid request + '404': + description: Not found + post: + tags: + - fake + summary: | + Fake endpoint for testing various parameters + 假端點 + 偽のエンドポイント + 가짜 엔드 포인트 + description: | + Fake endpoint for testing various parameters + 假端點 + 偽のエンドポイント + 가짜 엔드 포인트 + operationId: testEndpointParameters + consumes: + - application/xml; charset=utf-8 + - application/json; charset=utf-8 + produces: + - application/xml; charset=utf-8 + - application/json; charset=utf-8 + parameters: + - name: integer + type: integer + maximum: 100 + minimum: 10 + in: formData + description: None + - name: int32 + type: integer + format: int32 + maximum: 200 + minimum: 20 + in: formData + description: None + - name: int64 + type: integer + format: int64 + in: formData + description: None + - name: number + type: number + maximum: 543.2 + minimum: 32.1 + in: formData + description: None + required: true + - name: float + type: number + format: float + maximum: 987.6 + in: formData + description: None + - name: double + type: number + in: formData + format: double + maximum: 123.4 + minimum: 67.8 + required: true + description: None + - name: string + type: string + pattern: /[a-z]/i + in: formData + description: None + - name: pattern_without_delimiter + type: string + pattern: "^[A-Z].*" + in: formData + description: None + required: true + - name: byte + type: string + format: byte + in: formData + description: None + required: true + - name: binary + type: string + format: binary + in: formData + description: None + - name: date + type: string + format: date + in: formData + description: None + - name: dateTime + type: string + format: date-time + in: formData + description: None + - name: password + type: string + format: password + maxLength: 64 + minLength: 10 + in: formData + description: None + - name: callback + type: string + in: formData + description: None + responses: + '400': + description: Invalid username supplied + '404': + description: User not found + security: + - http_basic_test: [] +securityDefinitions: + 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 + api_key: + type: apiKey + name: api_key + in: header + http_basic_test: + type: basic +definitions: + Order: + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Category + User: + type: object + properties: + id: + type: integer + format: int64 + x-is-unique: true + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + x-is-unique: true + category: + $ref: '#/definitions/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/definitions/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + '$special[model.name]': + properties: + '$special[property.name]': + type: integer + format: int64 + xml: + name: '$special[model.name]' + Return: + description: Model for testing reserved words + properties: + return: + type: integer + format: int32 + xml: + name: Return + Name: + description: Model for testing model name same as property name + required: + - name + properties: + name: + type: integer + format: int32 + snake_case: + readOnly: true + type: integer + format: int32 + property: + type: string + 123Number: + type: integer + readOnly: true + xml: + name: Name + 200_response: + description: Model for testing model name starting with number + properties: + name: + type: integer + format: int32 + class: + type: string + xml: + name: Name + Dog: + allOf: + - $ref: '#/definitions/Animal' + - type: object + properties: + breed: + type: string + Cat: + allOf: + - $ref: '#/definitions/Animal' + - type: object + properties: + declawed: + type: boolean + Animal: + type: object + discriminator: className + required: + - className + properties: + className: + type: string + color: + type: string + default: 'red' + AnimalFarm: + type: array + items: + $ref: '#/definitions/Animal' + format_test: + type: object + required: + - number + - byte + - date + - password + properties: + integer: + type: integer + maximum: 100 + minimum: 10 + int32: + type: integer + format: int32 + maximum: 200 + minimum: 20 + int64: + type: integer + format: int64 + number: + maximum: 543.2 + minimum: 32.1 + type: number + float: + type: number + format: float + maximum: 987.6 + minimum: 54.3 + double: + type: number + format: double + maximum: 123.4 + minimum: 67.8 + string: + type: string + pattern: /[a-z]/i + byte: + type: string + format: byte + binary: + type: string + format: binary + date: + type: string + format: date + dateTime: + type: string + format: date-time + uuid: + type: string + format: uuid + password: + type: string + format: password + maxLength: 64 + minLength: 10 + EnumClass: + type: string + default: '-efg' + enum: + - _abc + - '-efg' + - (xyz) + Enum_Test: + type: object + properties: + enum_string: + type: string + enum: + - UPPER + - lower + enum_integer: + type: integer + format: int32 + enum: + - 1 + - -1 + enum_number: + type: number + format: double + enum: + - 1.1 + - -1.2 + AdditionalPropertiesClass: + type: object + properties: + map_property: + type: object + additionalProperties: + type: string + map_of_map_property: + type: object + additionalProperties: + type: object + additionalProperties: + type: string + MixedPropertiesAndAdditionalPropertiesClass: + type: object + properties: + uuid: + type: string + format: uuid + dateTime: + type: string + format: date-time + map: + type: object + additionalProperties: + $ref: '#/definitions/Animal' + List: + type: object + properties: + 123-list: + type: string + Client: + type: object + properties: + client: + type: string + ReadOnlyFirst: + type: object + properties: + bar: + type: string + readOnly: true + baz: + type: string + hasOnlyReadOnly: + type: object + properties: + bar: + type: string + readOnly: true + foo: + type: string + readOnly: true + MapTest: + type: object + properties: + map_map_of_string: + type: object + additionalProperties: + type: object + additionalProperties: + type: string + # comment out the following (map of map of enum) as many language not yet support this + #map_map_of_enum: + # type: object + # additionalProperties: + # type: object + # additionalProperties: + # type: string + # enum: + # - UPPER + # - lower + map_of_enum_string: + type: object + additionalProperties: + type: string + enum: + - UPPER + - lower + ArrayTest: + type: object + properties: + array_of_string: + type: array + items: + type: string + array_array_of_integer: + type: array + items: + type: array + items: + type: integer + format: int64 + array_array_of_model: + type: array + items: + type: array + items: + $ref: '#/definitions/ReadOnlyFirst' + # commented out the below test case for array of enum for the time being + # as not all language can handle it + #array_of_enum: + # type: array + # items: + # type: string + # enum: + # - UPPER + # - lower + NumberOnly: + type: object + properties: + JustNumber: + type: number + ArrayOfNumberOnly: + type: object + properties: + ArrayNumber: + type: array + items: + type: number + ArrayOfArrayOfNumberOnly: + type: object + properties: + ArrayArrayNumber: + type: array + items: + type: array + items: + type: number + EnumArrays: + type: object + properties: + just_symbol: + type: string + enum: + - ">=" + - "$" + array_enum: + type: array + items: + type: string + enum: + - fish + - crab + # comment out the following as 2d array of enum is not supported at the moment + #array_array_enum: + # type: array + # items: + # type: array + # items: + # type: string + # enum: + # - Cat + # - Dog +externalDocs: + description: Find out more about Swagger + url: 'http://swagger.io' diff --git a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/FakeApi.java b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/FakeApi.java index d1068513f0e..ba826f92d08 100644 --- a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/FakeApi.java +++ b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/FakeApi.java @@ -10,8 +10,8 @@ import okhttp3.RequestBody; import io.swagger.client.model.Client; import org.joda.time.LocalDate; -import org.joda.time.DateTime; import java.math.BigDecimal; +import org.joda.time.DateTime; import java.util.ArrayList; import java.util.HashMap; @@ -26,6 +26,9 @@ public interface FakeApi { * @return Call<Client> */ + @Headers({ + "Content-Type:application/json" + }) @PATCH("fake") Call testClientModel( @retrofit2.http.Body Client body diff --git a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/PetApi.java index 3f61279a66b..64ebfe75750 100644 --- a/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/java/retrofit2/src/main/java/io/swagger/client/api/PetApi.java @@ -9,8 +9,8 @@ import retrofit2.http.*; import okhttp3.RequestBody; import io.swagger.client.model.Pet; -import java.io.File; import io.swagger.client.model.ModelApiResponse; +import java.io.File; import java.util.ArrayList; import java.util.HashMap; @@ -25,6 +25,9 @@ public interface PetApi { * @return Call<Void> */ + @Headers({ + "Content-Type:application/json" + }) @POST("pet") Call addPet( @retrofit2.http.Body Pet body @@ -86,6 +89,9 @@ public interface PetApi { * @return Call<Void> */ + @Headers({ + "Content-Type:application/json" + }) @PUT("pet") Call updatePet( @retrofit2.http.Body Pet body