This is an automated email from the ASF dual-hosted git repository. zregvart pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new b753eec CAMEL-13490: Consider API key in query paramete... b753eec is described below commit b753eecae3ddeabbd2a3391fffbeb3c6abe001ed Author: Zoran Regvart <zregv...@apache.org> AuthorDate: Tue May 7 13:24:59 2019 +0200 CAMEL-13490: Consider API key in query paramete... ...rs when configuring REST producers This will include any query API keys that are specified in the security requirement for a operation in the query parameters configured on the `rest` endpoint. --- .../rest/swagger/RestSwaggerEndpoint.java | 58 +- .../rest/swagger/RestSwaggerComponentTest.java | 46 + .../rest/swagger/RestSwaggerEndpointTest.java | 40 +- .../src/test/resources/alt-petstore.json | 1039 ++++++++++++++++++++ 4 files changed, 1164 insertions(+), 19 deletions(-) diff --git a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java index 52fb3b6..ddbf410 100644 --- a/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java +++ b/components/camel-rest-swagger/src/main/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpoint.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -28,6 +29,7 @@ import java.util.Map.Entry; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.Optional.ofNullable; @@ -39,7 +41,11 @@ import io.swagger.models.Operation; import io.swagger.models.Path; import io.swagger.models.Scheme; import io.swagger.models.Swagger; +import io.swagger.models.auth.ApiKeyAuthDefinition; +import io.swagger.models.auth.In; +import io.swagger.models.auth.SecuritySchemeDefinition; import io.swagger.models.parameters.Parameter; +import io.swagger.models.parameters.QueryParameter; import io.swagger.parser.SwaggerParser; import io.swagger.util.Json; @@ -122,16 +128,15 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { + " any value present in the Swagger specification. Overrides all other configuration.", label = "producer") private String produces; - @UriPath( - description = "Path to the Swagger specification file. The scheme, host base path are taken from this" - + " specification, but these can be overridden with properties on the component or endpoint level. If not" - + " given the component tries to load `swagger.json` resource from the classpath. Note that the `host` defined on the" - + " component and endpoint of this Component should contain the scheme, hostname and optionally the" - + " port in the URI syntax (i.e. `http://api.example.com:8080`). Overrides component configuration." - + " The Swagger specification can be loaded from different sources by prefixing with file: classpath: http: https:." - + " Support for https is limited to using the JDK installed UrlHandler, and as such it can be cumbersome to setup" - + " TLS/SSL certificates for https (such as setting a number of javax.net.ssl JVM system properties)." - + " How to do that consult the JDK documentation for UrlHandler.", + @UriPath(description = "Path to the Swagger specification file. The scheme, host base path are taken from this" + + " specification, but these can be overridden with properties on the component or endpoint level. If not" + + " given the component tries to load `swagger.json` resource from the classpath. Note that the `host` defined on the" + + " component and endpoint of this Component should contain the scheme, hostname and optionally the" + + " port in the URI syntax (i.e. `http://api.example.com:8080`). Overrides component configuration." + + " The Swagger specification can be loaded from different sources by prefixing with file: classpath: http: https:." + + " Support for https is limited to using the JDK installed UrlHandler, and as such it can be cumbersome to setup" + + " TLS/SSL certificates for https (such as setting a number of javax.net.ssl JVM system properties)." + + " How to do that consult the JDK documentation for UrlHandler.", defaultValue = RestSwaggerComponent.DEFAULT_SPECIFICATION_URI_STR, defaultValueNote = "By default loads `swagger.json` file", label = "producer") private URI specificationUri = RestSwaggerComponent.DEFAULT_SPECIFICATION_URI; @@ -348,13 +353,14 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { parameters.put("produces", determinedProducers); } - final String queryParameters = operation.getParameters().stream().filter(p -> "query".equals(p.getIn())) - .map(this::queryParameter).collect(Collectors.joining("&")); + final String queryParameters = determineQueryParameters(swagger, operation).map(this::queryParameter) + .collect(Collectors.joining("&")); if (isNotEmpty(queryParameters)) { parameters.put("queryParameters", queryParameters); } - // pass properties that might be applied if the delegate component is created, i.e. if it's not + // pass properties that might be applied if the delegate component is + // created, i.e. if it's not // present in the Camel Context already final Map<String, Object> componentParameters = new HashMap<>(); @@ -525,6 +531,32 @@ public final class RestSwaggerEndpoint extends DefaultEndpoint { return null; } + static Stream<Parameter> determineQueryParameters(final Swagger swagger, final Operation operation) { + final List<Map<String, List<String>>> securityRequirements = operation.getSecurity(); + final List<QueryParameter> apiKeyQueryParameters = new ArrayList<>(); + if (securityRequirements != null) { + final Map<String, SecuritySchemeDefinition> securityDefinitions = swagger.getSecurityDefinitions(); + + for (final Map<String, List<String>> securityRequirement : securityRequirements) { + for (final String securityRequirementName : securityRequirement.keySet()) { + final SecuritySchemeDefinition securitySchemeDefinition = securityDefinitions + .get(securityRequirementName); + if (securitySchemeDefinition instanceof ApiKeyAuthDefinition) { + final ApiKeyAuthDefinition apiKeyDefinition = (ApiKeyAuthDefinition) securitySchemeDefinition; + + if (apiKeyDefinition.getIn() == In.QUERY) { + apiKeyQueryParameters.add(new QueryParameter().name(apiKeyDefinition.getName()) + .required(true).type("string").description(apiKeyDefinition.getDescription())); + } + } + } + } + } + + return Stream.concat(apiKeyQueryParameters.stream(), + operation.getParameters().stream().filter(p -> "query".equals(p.getIn()))); + } + static String hostFrom(final RestConfiguration restConfiguration) { if (restConfiguration == null) { return null; diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java index 7ef28b8..2165aa2 100644 --- a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java +++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerComponentTest.java @@ -23,6 +23,8 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; @@ -113,6 +115,39 @@ public class RestSwaggerComponentTest extends CamelTestSupport { } @Test + public void shouldBeGettingPetsByIdWithApiKeysInHeader() { + final Map<String, Object> headers = new HashMap<>(); + headers.put("petId", 14); + headers.put("api_key", "dolphins"); + final Pet pet = template.requestBodyAndHeaders("direct:getPetById", NO_BODY, headers, Pet.class); + + assertNotNull(pet); + + assertEquals(Integer.valueOf(14), pet.id); + assertEquals("Olafur Eliason Arnalds", pet.name); + + petstore.verify( + getRequestedFor(urlEqualTo("/v2/pet/14")).withHeader("Accept", equalTo("application/xml, application/json")) + .withHeader("api_key", equalTo("dolphins"))); + } + + @Test + public void shouldBeGettingPetsByIdWithApiKeysInQueryParameter() { + final Map<String, Object> headers = new HashMap<>(); + headers.put("petId", 14); + headers.put("api_key", "dolphins"); + final Pet pet = template.requestBodyAndHeaders("altPetStore:getPetById", NO_BODY, headers, Pet.class); + + assertNotNull(pet); + + assertEquals(Integer.valueOf(14), pet.id); + assertEquals("Olafur Eliason Arnalds", pet.name); + + petstore.verify(getRequestedFor(urlEqualTo("/v2/pet/14?api_key=dolphins")).withHeader("Accept", + equalTo("application/xml, application/json"))); + } + + @Test public void shouldBeGettingPetsByStatus() { final Pets pets = template.requestBodyAndHeader("direct:findPetsByStatus", NO_BODY, "status", "available", Pets.class); @@ -136,6 +171,13 @@ public class RestSwaggerComponentTest extends CamelTestSupport { camelContext.addComponent("petStore", component); + final RestSwaggerComponent altPetStore = new RestSwaggerComponent(); + altPetStore.setComponentName(componentName); + altPetStore.setHost("http://localhost:" + petstore.port()); + altPetStore.setSpecificationUri(RestSwaggerComponentTest.class.getResource("/alt-petstore.json").toURI()); + + camelContext.addComponent("altPetStore", altPetStore); + return camelContext; } @@ -184,6 +226,10 @@ public class RestSwaggerComponentTest extends CamelTestSupport { petstore.stubFor(get(urlPathEqualTo("/v2/pet/findByStatus")).withQueryParam("status", equalTo("available")) .willReturn(aResponse().withStatus(HttpURLConnection.HTTP_OK).withBody( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><pets><Pet><id>1</id><name>Olafur Eliason Arnalds</name></Pet><Pet><name>Jean-Luc Picard</name></Pet></pets>"))); + + petstore.stubFor(get(urlEqualTo("/v2/pet/14?api_key=dolphins")) + .willReturn(aResponse().withStatus(HttpURLConnection.HTTP_OK).withBody( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Pet><id>14</id><name>Olafur Eliason Arnalds</name></Pet>"))); } } diff --git a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java index 0a8d495..dad4eef 100644 --- a/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java +++ b/components/camel-rest-swagger/src/test/java/org/apache/camel/component/rest/swagger/RestSwaggerEndpointTest.java @@ -26,6 +26,8 @@ import java.util.Map; import io.swagger.models.Operation; import io.swagger.models.Scheme; import io.swagger.models.Swagger; +import io.swagger.models.auth.ApiKeyAuthDefinition; +import io.swagger.models.auth.In; import io.swagger.models.parameters.Parameter; import io.swagger.models.parameters.PathParameter; import io.swagger.models.parameters.QueryParameter; @@ -119,18 +121,18 @@ public class RestSwaggerEndpointTest { .isEqualTo("/"); restConfiguration.setContextPath("/rest"); - assertThat(endpoint.determineBasePath(swagger)) - .as("When base path is specified in REST configuration and not specified in component the base path should be from the REST configuration") + assertThat(endpoint.determineBasePath(swagger)).as( + "When base path is specified in REST configuration and not specified in component the base path should be from the REST configuration") .isEqualTo("/rest"); swagger.basePath("/specification"); - assertThat(endpoint.determineBasePath(swagger)) - .as("When base path is specified in the specification it should take precedence the one specified in the REST configuration") + assertThat(endpoint.determineBasePath(swagger)).as( + "When base path is specified in the specification it should take precedence the one specified in the REST configuration") .isEqualTo("/specification"); component.setBasePath("/component"); - assertThat(endpoint.determineBasePath(swagger)) - .as("When base path is specified on the component it should take precedence over Swagger specification and REST configuration") + assertThat(endpoint.determineBasePath(swagger)).as( + "When base path is specified on the component it should take precedence over Swagger specification and REST configuration") .isEqualTo("/component"); endpoint.setBasePath("/endpoint"); @@ -328,6 +330,32 @@ public class RestSwaggerEndpointTest { } @Test + public void shouldIncludeApiKeysQueryParameters() { + final CamelContext camelContext = mock(CamelContext.class); + + final RestSwaggerComponent component = new RestSwaggerComponent(); + component.setCamelContext(camelContext); + + final RestSwaggerEndpoint endpoint = new RestSwaggerEndpoint("uri", "remaining", component, + Collections.emptyMap()); + endpoint.setHost("http://petstore.swagger.io"); + + final Swagger swagger = new Swagger(); + final ApiKeyAuthDefinition apiKeys = new ApiKeyAuthDefinition("key", In.HEADER); + swagger.securityDefinition("apiKeys", apiKeys); + + final Operation operation = new Operation().parameter(new QueryParameter().name("q").required(true)); + operation.addSecurity("apiKeys", Collections.emptyList()); + + assertThat(endpoint.determineEndpointParameters(swagger, operation)) + .containsOnly(entry("host", "http://petstore.swagger.io"), entry("queryParameters", "q={q}")); + + apiKeys.setIn(In.QUERY); + assertThat(endpoint.determineEndpointParameters(swagger, operation)) + .containsOnly(entry("host", "http://petstore.swagger.io"), entry("queryParameters", "key={key}&q={q}")); + } + + @Test public void shouldLoadSwaggerSpecifications() throws IOException { final CamelContext camelContext = mock(CamelContext.class); when(camelContext.getClassResolver()).thenReturn(new DefaultClassResolver()); diff --git a/components/camel-rest-swagger/src/test/resources/alt-petstore.json b/components/camel-rest-swagger/src/test/resources/alt-petstore.json new file mode 100644 index 0000000..98fb926 --- /dev/null +++ b/components/camel-rest-swagger/src/test/resources/alt-petstore.json @@ -0,0 +1,1039 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). 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://swagger.io/terms/", + "contact": { + "email": "apit...@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/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/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": { + "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": "multi" + } + ], + "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": "Muliple 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": "multi" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Pet" + } + } + }, + "400": { + "description": "Invalid tag value" + } + }, + "security": [ + { + "petstore_auth": [ + "write:pets", + "read:pets" + ] + } + ], + "deprecated": true + } + }, + "/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 ID supplied" + }, + "404": { + "description": "Pet not found" + } + }, + "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 >= 1 and <= 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": 10.0, + "minimum": 1.0, + "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 positive integer value. Negative or non-integer values 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": "integer", + "minimum": 1.0, + "format": "int64" + } + ], + "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 token 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 updated", + "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" + } + } + } + } + }, + "securityDefinitions": { + "petstore_auth": { + "type": "oauth2", + "authorizationUrl": "http://petstore.swagger.io/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": "query" + } + }, + "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" + }, + "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" + }, + "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" + } + } + } + }, + "externalDocs": { + "description": "Find out more about Swagger", + "url": "http://swagger.io" + } +}