This is an automated email from the ASF dual-hosted git repository.
jamesnetherton pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 7adea167b8f CAMEL-18221: Enable REST OpenAPI component to handle YAML
OpenAPI documents
7adea167b8f is described below
commit 7adea167b8ff850165daf844d23c4980e375a251
Author: James Netherton <[email protected]>
AuthorDate: Thu Jun 23 10:57:26 2022 +0100
CAMEL-18221: Enable REST OpenAPI component to handle YAML OpenAPI documents
---
components/camel-rest-openapi/pom.xml | 5 +
.../rest/openapi/RestOpenApiEndpoint.java | 29 +-
.../component/rest/openapi/RestOpenApiHelper.java | 43 ++
.../openapi/RestOpenApiComponentV3YamlTest.java | 267 +++++++
.../rest/openapi/RestOpenApiComponentYamlTest.java | 267 +++++++
.../rest/openapi/RestOpenApiHelperTest.java | 77 ++
.../src/test/resources/alt-openapi.yaml | 792 ++++++++++++++++++++
.../src/test/resources/alt-petstore.yaml | 699 ++++++++++++++++++
.../src/test/resources/openapi-v3.yaml | 802 +++++++++++++++++++++
.../src/test/resources/openapi.yaml | 699 ++++++++++++++++++
.../org/apache/camel/spi/ContentTypeAware.java | 36 +
.../impl/engine/DefaultResourceResolvers.java | 146 ++--
.../org/apache/camel/support/ResourceHelper.java | 42 +-
13 files changed, 3805 insertions(+), 99 deletions(-)
diff --git a/components/camel-rest-openapi/pom.xml
b/components/camel-rest-openapi/pom.xml
index a4642cd6dcb..a886480c64c 100644
--- a/components/camel-rest-openapi/pom.xml
+++ b/components/camel-rest-openapi/pom.xml
@@ -60,6 +60,11 @@
<version>${apicurio-version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.dataformat</groupId>
+ <artifactId>jackson-dataformat-yaml</artifactId>
+ </dependency>
+
<!-- test -->
<dependency>
<groupId>org.apache.camel</groupId>
diff --git
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
index 96dd0266535..a9018a03d98 100644
---
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
+++
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiEndpoint.java
@@ -16,6 +16,7 @@
*/
package org.apache.camel.component.rest.openapi;
+import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
@@ -35,8 +36,10 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.apicurio.datamodels.Library;
import io.apicurio.datamodels.core.models.Document;
import io.apicurio.datamodels.core.models.common.SecurityRequirement;
@@ -65,6 +68,7 @@ import org.apache.camel.ExchangePattern;
import org.apache.camel.Processor;
import org.apache.camel.Producer;
import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.Resource;
import org.apache.camel.spi.RestConfiguration;
import org.apache.camel.spi.UriEndpoint;
import org.apache.camel.spi.UriParam;
@@ -72,6 +76,7 @@ import org.apache.camel.spi.UriPath;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.DefaultEndpoint;
import org.apache.camel.support.ResourceHelper;
+import org.apache.camel.util.FileUtil;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import org.apache.camel.util.UnsafeUriCharactersEncoder;
@@ -800,16 +805,28 @@ public final class RestOpenApiEndpoint extends
DefaultEndpoint {
* @return the specification
*/
static Document loadSpecificationFrom(final CamelContext camelContext,
final URI uri) {
- final ObjectMapper mapper = new ObjectMapper();
-
final String uriAsString = uri.toString();
+ JsonFactory factory = null;
- try (InputStream stream =
ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext,
uriAsString)) {
- final JsonNode node = mapper.readTree(stream);
+ try {
+ final Resource resource =
ResourceHelper.resolveMandatoryResource(camelContext, uriAsString);
- return Library.readDocument(node);
- } catch (final Exception e) {
+ try (InputStream stream = resource.getInputStream()) {
+ if (stream == null) {
+ String resourcePath = FileUtil.compactPath(uriAsString,
'/');
+ throw new FileNotFoundException("Cannot find resource: " +
resourcePath + " for URI: " + uri);
+ }
+
+ if (RestOpenApiHelper.isYamlResource(resource)) {
+ factory = new YAMLFactory();
+ }
+
+ ObjectMapper mapper = new ObjectMapper(factory);
+ final JsonNode node = mapper.readTree(stream);
+ return Library.readDocument(node);
+ }
+ } catch (final Exception e) {
throw new IllegalArgumentException(
"The given OpenApi specification could not be loaded from
`" + uri
+ "`. Tried loading using
Camel's resource resolution and using OpenApi's own resource resolution."
diff --git
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
index 2dcc16880bc..4af6a0772c8 100644
---
a/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
+++
b/components/camel-rest-openapi/src/main/java/org/apache/camel/component/rest/openapi/RestOpenApiHelper.java
@@ -16,9 +16,16 @@
*/
package org.apache.camel.component.rest.openapi;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import org.apache.camel.spi.ContentTypeAware;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.StringHelper;
import static org.apache.camel.util.StringHelper.notEmpty;
@@ -26,6 +33,8 @@ import static org.apache.camel.util.StringHelper.notEmpty;
final class RestOpenApiHelper {
private static final Pattern HOST_PATTERN =
Pattern.compile("https?://[^:]+(:\\d+)?", Pattern.CASE_INSENSITIVE);
+ private static final List<String> YAML_CONTENT_TYPES =
Arrays.asList("application/yaml", "application/yml",
+ "text/yaml", "text/yml", "text/x-yaml");
private RestOpenApiHelper() {
// utility class
@@ -35,6 +44,23 @@ final class RestOpenApiHelper {
return notEmpty(given, name);
}
+ /**
+ * Determines if a {@link Resource} contains YAML content.
+ *
+ * @param resource The resource to inspect
+ * @return {@code true} if the resource has YAML content,
otherwise {@code false}
+ */
+ public static boolean isYamlResource(Resource resource) {
+ Objects.requireNonNull(resource, "resource cannot be null");
+
+ if (resource instanceof ContentTypeAware) {
+ String contentType = ((ContentTypeAware)
resource).getContentType();
+ return isYamlResourceLocation(resource.getLocation()) ||
isYamlContentType(contentType);
+ }
+
+ return isYamlResourceLocation(resource.getLocation());
+ }
+
static String isHostParam(final String given) {
final String hostUri = StringHelper.notEmpty(given, "host");
@@ -47,4 +73,21 @@ final class RestOpenApiHelper {
return hostUri;
}
+
+ private static boolean isYamlContentType(String contentType) {
+ if (ObjectHelper.isEmpty(contentType)) {
+ return false;
+ }
+ return Stream.of(contentType.split(";"))
+ .map(String::trim)
+ .anyMatch(YAML_CONTENT_TYPES::contains);
+ }
+
+ private static boolean isYamlResourceLocation(String location) {
+ if (ObjectHelper.isEmpty(location)) {
+ return false;
+ }
+ return location.toLowerCase().endsWith(".yml") ||
location.toLowerCase().endsWith(".yaml");
+ }
+
}
diff --git
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentV3YamlTest.java
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentV3YamlTest.java
new file mode 100644
index 00000000000..d6146f0ae85
--- /dev/null
+++
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentV3YamlTest.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.rest.openapi;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+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;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.RestEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static
com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class RestOpenApiComponentV3YamlTest extends CamelTestSupport {
+
+ public static WireMockServer petstore = new
WireMockServer(wireMockConfig().dynamicPort());
+
+ static final Object NO_BODY = null;
+
+ public String componentName;
+
+ @BeforeAll
+ public static void startWireMockServer() {
+ petstore.start();
+ }
+
+ @AfterAll
+ public static void stopWireMockServer() {
+ petstore.stop();
+ }
+
+ @Override
+ public void setUp() {
+ }
+
+ @BeforeEach
+ public void resetWireMock() {
+ petstore.resetRequests();
+ }
+
+ public void doSetUp(String componentName) throws Exception {
+ this.componentName = componentName;
+ super.setUp();
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeAddingPets(String componentName) throws Exception {
+ doSetUp(componentName);
+
+ final Pet pet = new Pet();
+ pet.name = "Jean-Luc Picard";
+
+ final Pet created = template.requestBody("direct:addPet", pet,
Pet.class);
+
+ assertNotNull(created);
+
+ assertEquals(Integer.valueOf(14), created.id);
+
+ petstore.verify(
+
postRequestedFor(urlEqualTo("/api/v3/pet")).withHeader("Accept",
equalTo("application/xml, application/json"))
+ .withHeader("Content-Type",
equalTo("application/xml")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsById(String componentName) throws Exception
{
+ doSetUp(componentName);
+
+ final Pet pet = template.requestBodyAndHeader("direct:getPetById",
NO_BODY, "petId", 14, Pet.class);
+
+ assertNotNull(pet);
+
+ assertEquals(Integer.valueOf(14), pet.id);
+ assertEquals("Olafur Eliason Arnalds", pet.name);
+
+
petstore.verify(getRequestedFor(urlEqualTo("/api/v3/pet/14")).withHeader("Accept",
+ equalTo("application/xml, application/json")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdSpecifiedInEndpointParameters(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ final Pet pet =
template.requestBody("direct:getPetByIdWithEndpointParams", NO_BODY, Pet.class);
+
+ assertNotNull(pet);
+
+ assertEquals(Integer.valueOf(14), pet.id);
+ assertEquals("Olafur Eliason Arnalds", pet.name);
+
+
petstore.verify(getRequestedFor(urlEqualTo("/api/v3/pet/14")).withHeader("Accept",
+ equalTo("application/xml, application/json")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdWithApiKeysInHeader(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ 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("/api/v3/pet/14")).withHeader("Accept",
equalTo("application/xml, application/json"))
+ .withHeader("api_key", equalTo("dolphins")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdWithApiKeysInQueryParameter(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ 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("/api/v3/pet/14?api_key=dolphins")).withHeader("Accept",
+ equalTo("application/xml, application/json")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByStatus(String componentName) throws
Exception {
+ doSetUp(componentName);
+
+ final Pets pets =
template.requestBodyAndHeader("direct:findPetsByStatus", NO_BODY, "status",
"available",
+ Pets.class);
+
+ assertNotNull(pets);
+ assertNotNull(pets.pets);
+ assertEquals(2, pets.pets.size());
+
+ petstore.verify(
+
getRequestedFor(urlPathEqualTo("/api/v3/pet/findByStatus")).withQueryParam("status",
equalTo("available"))
+ .withHeader("Accept", equalTo("application/xml,
application/json")));
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ final CamelContext camelContext = super.createCamelContext();
+
+ final RestOpenApiComponent component = new RestOpenApiComponent();
+ component.setComponentName(componentName);
+ component.setHost("http://localhost:" + petstore.port());
+
component.setSpecificationUri(RestOpenApiComponentV3YamlTest.class.getResource("/openapi-v3.yaml").toURI());
+
+ camelContext.addComponent("petStore", component);
+
+ final RestOpenApiComponent altPetStore = new RestOpenApiComponent();
+ altPetStore.setComponentName(componentName);
+ altPetStore.setHost("http://localhost:" + petstore.port());
+
altPetStore.setSpecificationUri(RestOpenApiComponentV3YamlTest.class.getResource("/alt-openapi.yaml").toURI());
+
+ camelContext.addComponent("altPetStore", altPetStore);
+
+ return camelContext;
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ final JAXBContext jaxbContext =
JAXBContext.newInstance(Pet.class, Pets.class);
+
+ final JaxbDataFormat jaxb = new JaxbDataFormat(jaxbContext);
+
+
jaxb.setJaxbProviderProperties(Collections.singletonMap(Marshaller.JAXB_FORMATTED_OUTPUT,
false));
+
+
from("direct:getPetById").to("petStore:getPetById").unmarshal(jaxb);
+
+
from("direct:getPetByIdWithEndpointParams").to("petStore:getPetById?petId=14").unmarshal(jaxb);
+
+
from("direct:addPet").marshal(jaxb).to("petStore:addPet").unmarshal(jaxb);
+
+
from("direct:findPetsByStatus").to("petStore:findPetsByStatus").unmarshal(jaxb);
+ }
+ };
+ }
+
+ public static Iterable<String> knownProducers() {
+ return Arrays.asList(RestEndpoint.DEFAULT_REST_PRODUCER_COMPONENTS);
+ }
+
+ @BeforeAll
+ public static void setupStubs() throws IOException, URISyntaxException {
+
petstore.stubFor(get(urlEqualTo("/openapi-v3.yaml")).willReturn(aResponse().withBody(
+
Files.readAllBytes(Paths.get(RestOpenApiComponentV3YamlTest.class.getResource("/openapi-v3.yaml").toURI())))));
+
+ petstore.stubFor(post(urlEqualTo("/api/v3/pet"))
+ .withRequestBody(equalTo(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"
standalone=\"yes\"?><Pet><name>Jean-Luc Picard</name></Pet>"))
+
.willReturn(aResponse().withStatus(HttpURLConnection.HTTP_CREATED)
+ .withBody("<?xml version=\"1.0\" encoding=\"UTF-8\"
standalone=\"yes\"?><Pet><id>14</id></Pet>")));
+
+ petstore.stubFor(
+
get(urlEqualTo("/api/v3/pet/14")).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>")));
+
+
petstore.stubFor(get(urlPathEqualTo("/api/v3/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("/api/v3/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-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentYamlTest.java
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentYamlTest.java
new file mode 100644
index 00000000000..eacc4850b98
--- /dev/null
+++
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiComponentYamlTest.java
@@ -0,0 +1,267 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.rest.openapi;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URISyntaxException;
+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;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import org.apache.camel.CamelContext;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.rest.RestEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static
com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class RestOpenApiComponentYamlTest extends CamelTestSupport {
+
+ public static WireMockServer petstore = new
WireMockServer(wireMockConfig().dynamicPort());
+
+ static final Object NO_BODY = null;
+
+ public String componentName;
+
+ @BeforeAll
+ public static void startWireMockServer() {
+ petstore.start();
+ }
+
+ @AfterAll
+ public static void stopWireMockServer() {
+ petstore.stop();
+ }
+
+ @Override
+ public void setUp() {
+ }
+
+ @BeforeEach
+ public void resetWireMock() {
+ petstore.resetRequests();
+ }
+
+ public void doSetUp(String componentName) throws Exception {
+ this.componentName = componentName;
+ super.setUp();
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeAddingPets(String componentName) throws Exception {
+ doSetUp(componentName);
+
+ final Pet pet = new Pet();
+ pet.name = "Jean-Luc Picard";
+
+ final Pet created = template.requestBody("direct:addPet", pet,
Pet.class);
+
+ assertNotNull(created);
+
+ assertEquals(Integer.valueOf(14), created.id);
+
+ petstore.verify(
+ postRequestedFor(urlEqualTo("/v2/pet")).withHeader("Accept",
equalTo("application/xml, application/json"))
+ .withHeader("Content-Type",
equalTo("application/xml")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsById(String componentName) throws Exception
{
+ doSetUp(componentName);
+
+ final Pet pet = template.requestBodyAndHeader("direct:getPetById",
NO_BODY, "petId", 14, 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")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdSpecifiedInEndpointParameters(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ final Pet pet =
template.requestBody("direct:getPetByIdWithEndpointParams", NO_BODY, 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")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdWithApiKeysInHeader(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ 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")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByIdWithApiKeysInQueryParameter(String
componentName) throws Exception {
+ doSetUp(componentName);
+
+ 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")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("knownProducers")
+ public void shouldBeGettingPetsByStatus(String componentName) throws
Exception {
+ doSetUp(componentName);
+
+ final Pets pets =
template.requestBodyAndHeader("direct:findPetsByStatus", NO_BODY, "status",
"available",
+ Pets.class);
+
+ assertNotNull(pets);
+ assertNotNull(pets.pets);
+ assertEquals(2, pets.pets.size());
+
+ petstore.verify(
+
getRequestedFor(urlPathEqualTo("/v2/pet/findByStatus")).withQueryParam("status",
equalTo("available"))
+ .withHeader("Accept", equalTo("application/xml,
application/json")));
+ }
+
+ @Override
+ protected CamelContext createCamelContext() throws Exception {
+ final CamelContext camelContext = super.createCamelContext();
+
+ final RestOpenApiComponent component = new RestOpenApiComponent();
+ component.setComponentName(componentName);
+ component.setHost("http://localhost:" + petstore.port());
+
component.setSpecificationUri(RestOpenApiComponentYamlTest.class.getResource("/openapi.yaml").toURI());
+
+ camelContext.addComponent("petStore", component);
+
+ final RestOpenApiComponent altPetStore = new RestOpenApiComponent();
+ altPetStore.setComponentName(componentName);
+ altPetStore.setHost("http://localhost:" + petstore.port());
+
altPetStore.setSpecificationUri(RestOpenApiComponentYamlTest.class.getResource("/alt-petstore.yaml").toURI());
+
+ camelContext.addComponent("altPetStore", altPetStore);
+
+ return camelContext;
+ }
+
+ @Override
+ protected RoutesBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ final JAXBContext jaxbContext =
JAXBContext.newInstance(Pet.class, Pets.class);
+
+ final JaxbDataFormat jaxb = new JaxbDataFormat(jaxbContext);
+
+
jaxb.setJaxbProviderProperties(Collections.singletonMap(Marshaller.JAXB_FORMATTED_OUTPUT,
false));
+
+
from("direct:getPetById").to("petStore:getPetById").unmarshal(jaxb);
+
+
from("direct:getPetByIdWithEndpointParams").to("petStore:getPetById?petId=14").unmarshal(jaxb);
+
+
from("direct:addPet").marshal(jaxb).to("petStore:addPet").unmarshal(jaxb);
+
+
from("direct:findPetsByStatus").to("petStore:findPetsByStatus").unmarshal(jaxb);
+ }
+ };
+ }
+
+ public static Iterable<String> knownProducers() {
+ return Arrays.asList(RestEndpoint.DEFAULT_REST_PRODUCER_COMPONENTS);
+ }
+
+ @BeforeAll
+ public static void setupStubs() throws IOException, URISyntaxException {
+
petstore.stubFor(get(urlEqualTo("/openapi.yaml")).willReturn(aResponse().withBody(
+
Files.readAllBytes(Paths.get(RestOpenApiComponentYamlTest.class.getResource("/openapi.yaml").toURI())))));
+
+ petstore.stubFor(post(urlEqualTo("/v2/pet"))
+ .withRequestBody(equalTo(
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"
standalone=\"yes\"?><Pet><name>Jean-Luc Picard</name></Pet>"))
+
.willReturn(aResponse().withStatus(HttpURLConnection.HTTP_CREATED)
+ .withBody("<?xml version=\"1.0\" encoding=\"UTF-8\"
standalone=\"yes\"?><Pet><id>14</id></Pet>")));
+
+ petstore.stubFor(
+
get(urlEqualTo("/v2/pet/14")).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>")));
+
+
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-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiHelperTest.java
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiHelperTest.java
index bebcabb8627..b653940c939 100644
---
a/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiHelperTest.java
+++
b/components/camel-rest-openapi/src/test/java/org/apache/camel/component/rest/openapi/RestOpenApiHelperTest.java
@@ -16,7 +16,16 @@
*/
package org.apache.camel.component.rest.openapi;
+import java.io.InputStream;
+import java.util.stream.Stream;
+
+import org.apache.camel.spi.ContentTypeAware;
+import org.apache.camel.spi.Resource;
+import org.apache.camel.support.ResourceSupport;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -51,4 +60,72 @@ public class RestOpenApiHelperTest {
assertThat(RestOpenApiHelper.isHostParam("http://api.example.com")).isEqualTo("http://api.example.com");
}
+ @ParameterizedTest
+ @MethodSource("contentTypes")
+ public void yamlResourceContentType(String contentType, boolean isValid) {
+ Resource resource = new FakeContentTypeAwareResource("https", null,
contentType);
+
assertThat(RestOpenApiHelper.isYamlResource(resource)).isEqualTo(isValid);
+ }
+
+ @ParameterizedTest
+ @MethodSource("resourceLocations")
+ public void yamlResourceLocation(String scheme, String location, boolean
isValid) {
+ Resource resource = new FakeContentTypeAwareResource(scheme, location,
null);
+
assertThat(RestOpenApiHelper.isYamlResource(resource)).isEqualTo(isValid);
+ }
+
+ private static Stream<Arguments> contentTypes() {
+ return Stream.of(
+ Arguments.of("application/yaml; charset=UTF-8", true),
+ Arguments.of("application/yml", true),
+ Arguments.of("text/yaml", true),
+ Arguments.of("text/yml", true),
+ Arguments.of("text/x-yaml", true),
+ Arguments.of("application/json", false),
+ Arguments.of("", false),
+ Arguments.of(null, false));
+ }
+
+ private static Stream<Arguments> resourceLocations() {
+ return Stream.of(
+ Arguments.of("https", "/api/openapi.yml", true),
+ Arguments.of("https", "/api/openapi.yaml", true),
+ Arguments.of("file", "/api/openapi.yaml", true),
+ Arguments.of("file", "/api/openapi.yml", true),
+ Arguments.of("file", "/api/openapi.YAML", true),
+ Arguments.of("classpath", "/api/openapi.yaml", true),
+ Arguments.of("classpath", "/api/openapi.yml", true),
+ Arguments.of("classpath", "/api/openapi.txt", false),
+ Arguments.of("classpath", "", false),
+ Arguments.of("classpath", null, false));
+ }
+
+ static final class FakeContentTypeAwareResource extends ResourceSupport
implements ContentTypeAware {
+ private String contentType;
+
+ FakeContentTypeAwareResource(String scheme, String location, String
contentType) {
+ super(scheme, location);
+ setContentType(contentType);
+ }
+
+ @Override
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+
+ @Override
+ public boolean exists() {
+ return true;
+ }
+
+ @Override
+ public InputStream getInputStream() {
+ return null;
+ }
+ }
}
diff --git a/components/camel-rest-openapi/src/test/resources/alt-openapi.yaml
b/components/camel-rest-openapi/src/test/resources/alt-openapi.yaml
new file mode 100644
index 00000000000..58a5dad461b
--- /dev/null
+++ b/components/camel-rest-openapi/src/test/resources/alt-openapi.yaml
@@ -0,0 +1,792 @@
+openapi: 3.0.2
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: "This is a sample Pet Store Server based on the OpenAPI 3.0
specification. You can find out more about\nSwagger at
[http://swagger.io](http://swagger.io). In the third iteration of the pet
store, we've switched to the design first approach!\nYou can now help us
improve the API whether it's by making changes to the definition itself or to
the code.\nThat way, with time, we can improve the API in general, and expose
some of the new features in OAS3.\n\nSome useful links:\n- [...]
+ termsOfService: http://swagger.io/terms/
+ contact:
+ email: [email protected]
+ license:
+ name: Apache 2.0
+ url: http://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.4
+externalDocs:
+ description: Find out more about Swagger
+ url: http://swagger.io
+servers:
+ - url: /api/v3
+tags:
+ - name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: http://swagger.io
+ - name: store
+ description: Operations about user
+ - name: user
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: http://swagger.io
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet
+ description: Update an existing pet by Id
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "405":
+ description: Validation exception
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store
+ description: Add a new pet to the store
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "405":
+ description: Invalid input
+ 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
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: false
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: false
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data
+ description: ""
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "405":
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet
+ description: ""
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ 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
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/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
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet
+ description: Place a new order in the store
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "405":
+ description: Invalid input
+ /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
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ 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
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ default:
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: Creates list of users with given input array
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: successful operation
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system
+ description: ""
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when toekn expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session
+ description: ""
+ operationId: logoutUser
+ parameters: []
+ responses:
+ default:
+ description: successful operation
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name
+ description: ""
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: 'The name that needs to be fetched. Use user1 for
testing. '
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ put:
+ tags:
+ - user
+ summary: Update user
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ default:
+ description: successful operation
+ delete:
+ tags:
+ - user
+ summary: Delete user
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Customer:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 100000
+ username:
+ type: string
+ example: fehguy
+ address:
+ type: array
+ xml:
+ name: addresses
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Address'
+ xml:
+ name: customer
+ Address:
+ type: object
+ properties:
+ street:
+ type: string
+ example: 437 Lytton
+ city:
+ type: string
+ example: Palo Alto
+ state:
+ type: string
+ example: CA
+ zip:
+ type: string
+ example: "94301"
+ xml:
+ name: address
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: [email protected]
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/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
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: query
diff --git a/components/camel-rest-openapi/src/test/resources/alt-petstore.yaml
b/components/camel-rest-openapi/src/test/resources/alt-petstore.yaml
new file mode 100644
index 00000000000..c7844acba33
--- /dev/null
+++ b/components/camel-rest-openapi/src/test/resources/alt-petstore.yaml
@@ -0,0 +1,699 @@
+swagger: "2.0"
+info:
+ description: 'This is a sample server Petstore server. You can find out
more about OpenApi 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: OpenApi Petstore
+ termsOfService: http://swagger.io/terms/
+ contact:
+ email: [email protected]
+ 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 OpenApi
+ url: http://swagger.io
diff --git a/components/camel-rest-openapi/src/test/resources/openapi-v3.yaml
b/components/camel-rest-openapi/src/test/resources/openapi-v3.yaml
new file mode 100644
index 00000000000..5c13af3176a
--- /dev/null
+++ b/components/camel-rest-openapi/src/test/resources/openapi-v3.yaml
@@ -0,0 +1,802 @@
+openapi: 3.0.2
+info:
+ title: Swagger Petstore - OpenAPI 3.0
+ description: "This is a sample Pet Store Server based on the OpenAPI 3.0
specification. You can find out more about\nSwagger at
[http://swagger.io](http://swagger.io). In the third iteration of the pet
store, we've switched to the design first approach!\nYou can now help us
improve the API whether it's by making changes to the definition itself or to
the code.\nThat way, with time, we can improve the API in general, and expose
some of the new features in OAS3.\n\nSome useful links:\n- [...]
+ termsOfService: http://swagger.io/terms/
+ contact:
+ email: [email protected]
+ license:
+ name: Apache 2.0
+ url: http://www.apache.org/licenses/LICENSE-2.0.html
+ version: 1.0.4
+externalDocs:
+ description: Find out more about Swagger
+ url: http://swagger.io
+servers:
+ - url: '{scheme}://{host}/{basePath}'
+ variables:
+ scheme:
+ enum:
+ - https
+ - http
+ default: https
+ host:
+ default: petstore.swagger.io
+ basePath:
+ default: /api/v3
+tags:
+ - name: pet
+ description: Everything about your Pets
+ externalDocs:
+ description: Find out more
+ url: http://swagger.io
+ - name: store
+ description: Operations about user
+ - name: user
+ description: Access to Petstore orders
+ externalDocs:
+ description: Find out more about our store
+ url: http://swagger.io
+paths:
+ /pet:
+ put:
+ tags:
+ - pet
+ summary: Update an existing pet
+ description: Update an existing pet by Id
+ operationId: updatePet
+ requestBody:
+ description: Update an existent pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ "405":
+ description: Validation exception
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Add a new pet to the store
+ description: Add a new pet to the store
+ operationId: addPet
+ requestBody:
+ description: Create a new pet in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ required: true
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "405":
+ description: Invalid input
+ 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
+ parameters:
+ - name: status
+ in: query
+ description: Status values that need to be considered for filter
+ required: false
+ explode: true
+ schema:
+ type: string
+ default: available
+ enum:
+ - available
+ - pending
+ - sold
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: tags
+ in: query
+ description: Tags to filter by
+ required: false
+ explode: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to return
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ "400":
+ description: Invalid ID supplied
+ "404":
+ description: Pet not found
+ security:
+ - api_key: []
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ post:
+ tags:
+ - pet
+ summary: Updates a pet in the store with form data
+ description: ""
+ operationId: updatePetWithForm
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet that needs to be updated
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: name
+ in: query
+ description: Name of pet that needs to be updated
+ schema:
+ type: string
+ - name: status
+ in: query
+ description: Status of pet that needs to be updated
+ schema:
+ type: string
+ responses:
+ "405":
+ description: Invalid input
+ security:
+ - petstore_auth:
+ - write:pets
+ - read:pets
+ delete:
+ tags:
+ - pet
+ summary: Deletes a pet
+ description: ""
+ operationId: deletePet
+ parameters:
+ - name: api_key
+ in: header
+ description: ""
+ required: false
+ schema:
+ type: string
+ - name: petId
+ in: path
+ description: Pet id to delete
+ required: true
+ schema:
+ 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
+ parameters:
+ - name: petId
+ in: path
+ description: ID of pet to update
+ required: true
+ schema:
+ type: integer
+ format: int64
+ - name: additionalMetadata
+ in: query
+ description: Additional Metadata
+ required: false
+ schema:
+ type: string
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/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
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ type: object
+ additionalProperties:
+ type: integer
+ format: int32
+ security:
+ - api_key: []
+ /store/order:
+ post:
+ tags:
+ - store
+ summary: Place an order for a pet
+ description: Place a new order in the store
+ operationId: placeOrder
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/Order'
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+ "405":
+ description: Invalid input
+ /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
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of order that needs to be fetched
+ required: true
+ schema:
+ type: integer
+ format: int64
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Order'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/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
+ parameters:
+ - name: orderId
+ in: path
+ description: ID of the order that needs to be deleted
+ required: true
+ schema:
+ type: integer
+ 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
+ requestBody:
+ description: Created user object
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ default:
+ description: successful operation
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ /user/createWithList:
+ post:
+ tags:
+ - user
+ summary: Creates list of users with given input array
+ description: Creates list of users with given input array
+ operationId: createUsersWithListInput
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ responses:
+ "200":
+ description: Successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ default:
+ description: successful operation
+ /user/login:
+ get:
+ tags:
+ - user
+ summary: Logs user into the system
+ description: ""
+ operationId: loginUser
+ parameters:
+ - name: username
+ in: query
+ description: The user name for login
+ required: false
+ schema:
+ type: string
+ - name: password
+ in: query
+ description: The password for login in clear text
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ headers:
+ X-Rate-Limit:
+ description: calls per hour allowed by the user
+ schema:
+ type: integer
+ format: int32
+ X-Expires-After:
+ description: date in UTC when toekn expires
+ schema:
+ type: string
+ format: date-time
+ content:
+ application/xml:
+ schema:
+ type: string
+ application/json:
+ schema:
+ type: string
+ "400":
+ description: Invalid username/password supplied
+ /user/logout:
+ get:
+ tags:
+ - user
+ summary: Logs out current logged in user session
+ description: ""
+ operationId: logoutUser
+ parameters: []
+ responses:
+ default:
+ description: successful operation
+ /user/{username}:
+ get:
+ tags:
+ - user
+ summary: Get user by user name
+ description: ""
+ operationId: getUserByName
+ parameters:
+ - name: username
+ in: path
+ description: 'The name that needs to be fetched. Use user1 for
testing. '
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: successful operation
+ content:
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+ put:
+ tags:
+ - user
+ summary: Update user
+ description: This can only be done by the logged in user.
+ operationId: updateUser
+ parameters:
+ - name: username
+ in: path
+ description: name that need to be deleted
+ required: true
+ schema:
+ type: string
+ requestBody:
+ description: Update an existent user in the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/User'
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: '#/components/schemas/User'
+ responses:
+ default:
+ description: successful operation
+ delete:
+ tags:
+ - user
+ summary: Delete user
+ description: This can only be done by the logged in user.
+ operationId: deleteUser
+ parameters:
+ - name: username
+ in: path
+ description: The name that needs to be deleted
+ required: true
+ schema:
+ type: string
+ responses:
+ "400":
+ description: Invalid username supplied
+ "404":
+ description: User not found
+components:
+ schemas:
+ Order:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ petId:
+ type: integer
+ format: int64
+ example: 198772
+ quantity:
+ type: integer
+ format: int32
+ example: 7
+ shipDate:
+ type: string
+ format: date-time
+ status:
+ type: string
+ description: Order Status
+ example: approved
+ enum:
+ - placed
+ - approved
+ - delivered
+ complete:
+ type: boolean
+ xml:
+ name: order
+ Customer:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 100000
+ username:
+ type: string
+ example: fehguy
+ address:
+ type: array
+ xml:
+ name: addresses
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/Address'
+ xml:
+ name: customer
+ Address:
+ type: object
+ properties:
+ street:
+ type: string
+ example: 437 Lytton
+ city:
+ type: string
+ example: Palo Alto
+ state:
+ type: string
+ example: CA
+ zip:
+ type: string
+ example: "94301"
+ xml:
+ name: address
+ Category:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 1
+ name:
+ type: string
+ example: Dogs
+ xml:
+ name: category
+ User:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ username:
+ type: string
+ example: theUser
+ firstName:
+ type: string
+ example: John
+ lastName:
+ type: string
+ example: James
+ email:
+ type: string
+ example: [email protected]
+ password:
+ type: string
+ example: "12345"
+ phone:
+ type: string
+ example: "12345"
+ userStatus:
+ type: integer
+ description: User Status
+ format: int32
+ example: 1
+ xml:
+ name: user
+ Tag:
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ name:
+ type: string
+ xml:
+ name: tag
+ Pet:
+ required:
+ - name
+ - photoUrls
+ type: object
+ properties:
+ id:
+ type: integer
+ format: int64
+ example: 10
+ name:
+ type: string
+ example: doggie
+ category:
+ $ref: '#/components/schemas/Category'
+ photoUrls:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ type: string
+ xml:
+ name: photoUrl
+ tags:
+ type: array
+ xml:
+ wrapped: true
+ items:
+ $ref: '#/components/schemas/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
+ xml:
+ name: '##default'
+ requestBodies:
+ Pet:
+ description: Pet object that needs to be added to the store
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ application/xml:
+ schema:
+ $ref: '#/components/schemas/Pet'
+ UserArray:
+ description: List of user object
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/User'
+ securitySchemes:
+ petstore_auth:
+ type: oauth2
+ flows:
+ implicit:
+ authorizationUrl: https://petstore3.swagger.io/oauth/authorize
+ scopes:
+ write:pets: modify pets in your account
+ read:pets: read your pets
+ api_key:
+ type: apiKey
+ name: api_key
+ in: header
diff --git a/components/camel-rest-openapi/src/test/resources/openapi.yaml
b/components/camel-rest-openapi/src/test/resources/openapi.yaml
new file mode 100644
index 00000000000..989b9b91457
--- /dev/null
+++ b/components/camel-rest-openapi/src/test/resources/openapi.yaml
@@ -0,0 +1,699 @@
+swagger: "2.0"
+info:
+ description: 'This is a sample server Petstore server. You can find out
more about OpenApi 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: [email protected]
+ 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: header
+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
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/ContentTypeAware.java
b/core/camel-api/src/main/java/org/apache/camel/spi/ContentTypeAware.java
new file mode 100644
index 00000000000..d50553c7a69
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/ContentTypeAware.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spi;
+
+/**
+ * Represents an object that can have an associated content type. Such as a
file or http resource.
+ */
+public interface ContentTypeAware {
+ /**
+ * The content type. Usually a value that conforms to the media type
specification outlined in RFC 6838.
+ *
+ * @return The content type string. Can be {@code null} if the content
type has not been set or is not known.
+ */
+ String getContentType();
+
+ /**
+ * Sets the content type.
+ *
+ * @param contentType The content type string
+ */
+ void setContentType(String contentType);
+}
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultResourceResolvers.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultResourceResolvers.java
index fcacb012fc1..5003b696be8 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultResourceResolvers.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultResourceResolvers.java
@@ -32,9 +32,8 @@ import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
-import javax.net.ssl.HttpsURLConnection;
-
import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.spi.ContentTypeAware;
import org.apache.camel.spi.Resource;
import org.apache.camel.spi.annotations.ResourceResolver;
import org.apache.camel.support.CamelContextHelper;
@@ -112,47 +111,7 @@ public final class DefaultResourceResolvers {
@Override
public Resource createResource(String location, String remaining) {
- return new ResourceSupport(SCHEME, location) {
- @Override
- public boolean exists() {
- URLConnection connection = null;
-
- try {
- connection = new URL(location).openConnection();
-
- if (connection instanceof HttpURLConnection) {
- return ((HttpURLConnection)
connection).getResponseCode() == HttpURLConnection.HTTP_OK;
- }
-
- return connection.getContentLengthLong() > 0;
- } catch (IOException e) {
- throw new IllegalArgumentException(e);
- } finally {
- // close the http connection to avoid
- // leaking gaps in case of an exception
- if (connection instanceof HttpURLConnection) {
- ((HttpURLConnection) connection).disconnect();
- }
- }
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- URLConnection con = new URL(location).openConnection();
- con.setUseCaches(false);
-
- try {
- return con.getInputStream();
- } catch (IOException e) {
- // close the http connection to avoid
- // leaking gaps in case of an exception
- if (con instanceof HttpURLConnection) {
- ((HttpURLConnection) con).disconnect();
- }
- throw e;
- }
- }
- };
+ return new HttpResource(SCHEME, location);
}
}
@@ -169,47 +128,7 @@ public final class DefaultResourceResolvers {
@Override
public Resource createResource(String location, String remaining) {
- return new ResourceSupport(SCHEME, location) {
- @Override
- public boolean exists() {
- URLConnection connection = null;
-
- try {
- connection = new URL(location).openConnection();
-
- if (connection instanceof HttpsURLConnection) {
- return ((HttpsURLConnection)
connection).getResponseCode() == HttpURLConnection.HTTP_OK;
- }
-
- return connection.getContentLengthLong() > 0;
- } catch (IOException e) {
- throw new IllegalArgumentException(e);
- } finally {
- // close the http connection to avoid
- // leaking gaps in case of an exception
- if (connection instanceof HttpsURLConnection) {
- ((HttpsURLConnection) connection).disconnect();
- }
- }
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- URLConnection con = new URL(location).openConnection();
- con.setUseCaches(false);
-
- try {
- return con.getInputStream();
- } catch (IOException e) {
- // close the http connection to avoid
- // leaking gaps in case of an exception
- if (con instanceof HttpsURLConnection) {
- ((HttpsURLConnection) con).disconnect();
- }
- throw e;
- }
- }
- };
+ return new HttpResource(SCHEME, location);
}
}
@@ -408,4 +327,63 @@ public final class DefaultResourceResolvers {
};
}
}
+
+ static final class HttpResource extends ResourceSupport implements
ContentTypeAware {
+ private String contentType;
+
+ HttpResource(String scheme, String location) {
+ super(scheme, location);
+ }
+
+ @Override
+ public boolean exists() {
+ URLConnection connection = null;
+
+ try {
+ connection = new URL(getLocation()).openConnection();
+
+ if (connection instanceof HttpURLConnection) {
+ return ((HttpURLConnection) connection).getResponseCode()
== HttpURLConnection.HTTP_OK;
+ }
+
+ return connection.getContentLengthLong() > 0;
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ } finally {
+ // close the http connection to avoid
+ // leaking gaps in case of an exception
+ if (connection instanceof HttpURLConnection) {
+ ((HttpURLConnection) connection).disconnect();
+ }
+ }
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ URLConnection con = new URL(getLocation()).openConnection();
+ con.setUseCaches(false);
+
+ try {
+ setContentType(con.getContentType());
+ return con.getInputStream();
+ } catch (IOException e) {
+ // close the http connection to avoid
+ // leaking gaps in case of an exception
+ if (con instanceof HttpURLConnection) {
+ ((HttpURLConnection) con).disconnect();
+ }
+ throw e;
+ }
+ }
+
+ @Override
+ public String getContentType() {
+ return this.contentType;
+ }
+
+ @Override
+ public void setContentType(String contentType) {
+ this.contentType = contentType;
+ }
+ }
}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/ResourceHelper.java
b/core/camel-support/src/main/java/org/apache/camel/support/ResourceHelper.java
index 048874a15e3..b7d70ba57d6 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/ResourceHelper.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/ResourceHelper.java
@@ -101,7 +101,7 @@ public final class ResourceHelper {
* </ul>
* If no prefix has been given, then the resource is loaded from the
classpath
* <p/>
- * If possible recommended to use {@link
#resolveMandatoryResourceAsUrl(org.apache.camel.spi.ClassResolver, String)}
+ * If possible recommended to use {@link
#resolveMandatoryResourceAsUrl(CamelContext, String)}
*
* @param camelContext the Camel Context
* @param uri URI of the resource
@@ -121,7 +121,7 @@ public final class ResourceHelper {
/**
* Resolves the resource.
* <p/>
- * If possible recommended to use {@link
#resolveMandatoryResourceAsUrl(org.apache.camel.spi.ClassResolver, String)}
+ * If possible recommended to use {@link
#resolveMandatoryResourceAsUrl(CamelContext, String)}
*
* @param camelContext the camel context
* @param uri URI of the resource
@@ -130,10 +130,7 @@ public final class ResourceHelper {
* @throws java.io.IOException is thrown if error loading the resource
*/
public static InputStream resolveResourceAsInputStream(CamelContext
camelContext, String uri) throws IOException {
- final ExtendedCamelContext ecc =
camelContext.adapt(ExtendedCamelContext.class);
- final ResourceLoader loader = ecc.getResourceLoader();
- final Resource resource = loader.resolveResource(uri);
-
+ final Resource resource = resolveResource(camelContext, uri);
return resource.getInputStream();
}
@@ -166,11 +163,38 @@ public final class ResourceHelper {
* @throws java.net.MalformedURLException if the URI is malformed
*/
public static URL resolveResourceAsUrl(CamelContext camelContext, String
uri) throws MalformedURLException {
+ final Resource resource = resolveResource(camelContext, uri);
+ return resource.getURL();
+ }
+
+ /**
+ * Resolves a mandatory resource.
+ *
+ * @param camelContext the camel context
+ * @param uri the uri of the resource
+ * @return the {@link Resource}
+ * @throws FileNotFoundException if the resource could not be found
+ */
+ public static Resource resolveMandatoryResource(CamelContext camelContext,
String uri) throws FileNotFoundException {
+ final Resource resource = resolveResource(camelContext, uri);
+ if (resource == null) {
+ String resolvedName = resolveUriPath(uri);
+ throw new FileNotFoundException("Cannot find resource: " +
resolvedName + " for URI: " + uri);
+ }
+ return resource;
+ }
+
+ /**
+ * Resolves a resource.
+ *
+ * @param camelContext the camel context
+ * @param uri the uri of the resource
+ * @return the {@link Resource}. Or <tt>null</tt> if not found
+ */
+ public static Resource resolveResource(CamelContext camelContext, String
uri) {
final ExtendedCamelContext ecc =
camelContext.adapt(ExtendedCamelContext.class);
final ResourceLoader loader = ecc.getResourceLoader();
- final Resource resource = loader.resolveResource(uri);
-
- return resource.getURL();
+ return loader.resolveResource(uri);
}
/**