This is an automated email from the ASF dual-hosted git repository. davsclaus 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 07dc1f1e046 CAMEL-18057: rest-dsl - Combine rest and linked route together as single route 07dc1f1e046 is described below commit 07dc1f1e046a74d9c144c794b226f4f4c79c2f4f Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Sep 23 17:20:15 2022 +0200 CAMEL-18057: rest-dsl - Combine rest and linked route together as single route --- .../org/apache/camel/spi/RestConfiguration.java | 19 ++++++ .../camel/impl/RestConfigurationConfigurer.java | 6 ++ .../java/org/apache/camel/impl/DefaultModel.java | 44 ++++++++++++++ .../org/apache/camel/model/rest/delete.json | 1 + .../resources/org/apache/camel/model/rest/get.json | 1 + .../org/apache/camel/model/rest/head.json | 1 + .../org/apache/camel/model/rest/patch.json | 1 + .../org/apache/camel/model/rest/post.json | 1 + .../resources/org/apache/camel/model/rest/put.json | 1 + .../apache/camel/model/rest/restConfiguration.json | 1 + .../model/rest/RestConfigurationDefinition.java | 39 ++++++++++++ .../apache/camel/model/rest/RestDefinition.java | 34 ++++++++++- .../apache/camel/model/rest/VerbDefinition.java | 14 +++++ .../component/rest/FromRestInlineRoutesTest.java | 69 ++++++++++++++++++++++ .../camel/component/rest/FromRestRouteIdTest.java | 64 ++++++++++++++++++++ .../RestConfigurationPropertiesConfigurer.java | 6 ++ .../camel-main-configuration-metadata.json | 1 + core/camel-main/src/main/docs/main.adoc | 3 +- .../camel/main/RestConfigurationProperties.java | 15 +++++ .../java/org/apache/camel/xml/in/ModelParser.java | 2 + docs/user-manual/modules/ROOT/pages/rest-dsl.adoc | 58 +++++++++++++++++- 21 files changed, 376 insertions(+), 5 deletions(-) diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/RestConfiguration.java b/core/camel-api/src/main/java/org/apache/camel/spi/RestConfiguration.java index 7de9c03a52d..1750f6710ee 100644 --- a/core/camel-api/src/main/java/org/apache/camel/spi/RestConfiguration.java +++ b/core/camel-api/src/main/java/org/apache/camel/spi/RestConfiguration.java @@ -64,6 +64,7 @@ public class RestConfiguration { private RestBindingMode bindingMode = RestBindingMode.off; private boolean skipBindingOnErrorCode = true; private boolean clientRequestValidation; + private boolean inlineRoutes; private boolean enableCORS; private String jsonDataFormat; private String xmlDataFormat; @@ -402,6 +403,24 @@ public class RestConfiguration { this.enableCORS = enableCORS; } + public boolean isInlineRoutes() { + return inlineRoutes; + } + + /** + * Inline routes in rest-dsl which are linked using direct endpoints. + * + * By default, each service in Rest DSL is an individual route, meaning that you would + * have at least two routes per service (rest-dsl, and the route linked from rest-dsl). + * Enabling this allows Camel to optimize and inline this as a single route, however + * this requires to use direct endpoints, which must be unique per service. + * + * This option is default <tt>false</tt>. + */ + public void setInlineRoutes(boolean inlineRoutes) { + this.inlineRoutes = inlineRoutes; + } + /** * Gets the name of the json data format. * <p/> diff --git a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/RestConfigurationConfigurer.java b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/RestConfigurationConfigurer.java index fa275642012..e79d85bc2a1 100644 --- a/core/camel-core-engine/src/generated/java/org/apache/camel/impl/RestConfigurationConfigurer.java +++ b/core/camel-core-engine/src/generated/java/org/apache/camel/impl/RestConfigurationConfigurer.java @@ -55,6 +55,8 @@ public class RestConfigurationConfigurer extends org.apache.camel.support.compon case "Host": target.setHost(property(camelContext, java.lang.String.class, value)); return true; case "hostnameresolver": case "HostNameResolver": target.setHostNameResolver(property(camelContext, java.lang.String.class, value)); return true; + case "inlineroutes": + case "InlineRoutes": target.setInlineRoutes(property(camelContext, boolean.class, value)); return true; case "jsondataformat": case "JsonDataFormat": target.setJsonDataFormat(property(camelContext, java.lang.String.class, value)); return true; case "port": @@ -112,6 +114,8 @@ public class RestConfigurationConfigurer extends org.apache.camel.support.compon case "Host": return java.lang.String.class; case "hostnameresolver": case "HostNameResolver": return java.lang.String.class; + case "inlineroutes": + case "InlineRoutes": return boolean.class; case "jsondataformat": case "JsonDataFormat": return java.lang.String.class; case "port": @@ -170,6 +174,8 @@ public class RestConfigurationConfigurer extends org.apache.camel.support.compon case "Host": return target.getHost(); case "hostnameresolver": case "HostNameResolver": return target.getHostNameResolver(); + case "inlineroutes": + case "InlineRoutes": return target.isInlineRoutes(); case "jsondataformat": case "JsonDataFormat": return target.getJsonDataFormat(); case "port": diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java index 477b67a62fa..d71893ccc87 100644 --- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java +++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultModel.java @@ -40,6 +40,7 @@ import org.apache.camel.model.BeanFactoryDefinition; import org.apache.camel.model.DataFormatDefinition; import org.apache.camel.model.DefaultRouteTemplateContext; import org.apache.camel.model.FaultToleranceConfigurationDefinition; +import org.apache.camel.model.FromDefinition; import org.apache.camel.model.Model; import org.apache.camel.model.ModelCamelContext; import org.apache.camel.model.ModelLifecycleStrategy; @@ -57,6 +58,7 @@ import org.apache.camel.model.RoutesDefinition; import org.apache.camel.model.TemplatedRouteBeanDefinition; import org.apache.camel.model.TemplatedRouteDefinition; import org.apache.camel.model.TemplatedRouteParameterDefinition; +import org.apache.camel.model.ToDefinition; import org.apache.camel.model.cloud.ServiceCallConfigurationDefinition; import org.apache.camel.model.rest.RestDefinition; import org.apache.camel.model.transformer.TransformerDefinition; @@ -178,6 +180,48 @@ public class DefaultModel implements Model { removeRouteDefinitions(list); + + // special if rest-dsl is inlining routes + if (camelContext.getRestConfiguration().isInlineRoutes()) { + List<RouteDefinition> allRoutes = new ArrayList<>(); + allRoutes.addAll(list); + allRoutes.addAll(this.routeDefinitions); + + List<RouteDefinition> toBeRemoved = new ArrayList<>(); + Map<String, RouteDefinition> directs = new HashMap<>(); + for (RouteDefinition r : allRoutes) { + // does the route start with direct, which is candidate for rest-dsl + FromDefinition from = r.getInput(); + if (from != null) { + String uri = from.getEndpointUri(); + if (uri != null && uri.startsWith("direct:")) { + directs.put(uri, r); + } + } + } + for (RouteDefinition r : allRoutes) { + // loop all rest routes + FromDefinition from = r.getInput(); + if (from != null) { + String uri = from.getEndpointUri(); + if (uri != null && uri.startsWith("rest:")) { + ToDefinition to = (ToDefinition) r.getOutputs().get(0); + String toUri = to.getEndpointUri(); + RouteDefinition toBeInlined = directs.get(toUri); + if (toBeInlined != null) { + toBeRemoved.add(toBeInlined); + // inline by replacing the outputs + r.getOutputs().clear(); + r.getOutputs().addAll(toBeInlined.getOutputs()); + } + } + } + } + // remove all the routes that was inlined + list.removeAll(toBeRemoved); + this.routeDefinitions.removeAll(toBeRemoved); + } + for (RouteDefinition r : list) { for (ModelLifecycleStrategy s : modelLifecycleStrategies) { s.onAddRouteDefinition(r); diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/delete.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/delete.json index 0a0900f2164..66f60b9b4e2 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/delete.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/delete.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/get.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/get.json index f4474a62ee9..366df91903a 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/get.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/get.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/head.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/head.json index cfd75e821c1..af317c58e3d 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/head.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/head.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/patch.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/patch.json index 729090cfd93..c013951b98f 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/patch.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/patch.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/post.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/post.json index 29ca52ed641..8dbaaa36c1e 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/post.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/post.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/put.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/put.json index bd9a5d8607f..728d0d886f6 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/put.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/put.json @@ -24,6 +24,7 @@ "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. This option will override what may be configured on a parent level The default value is false." }, "apiDocs": { "kind": "attribute", "displayName": "Api Docs", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether to include or exclude this rest operation in API documentation. The default value is true." }, "deprecated": { "kind": "attribute", "displayName": "Deprecated", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Marks this rest operation as deprecated in OpenApi documentation." }, + "routeId": { "kind": "attribute", "displayName": "Route Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of the route" }, "id": { "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" }, "description": { "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" } } diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/restConfiguration.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/restConfiguration.json index 582ff5e1c48..033245da87f 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/restConfiguration.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/rest/restConfiguration.json @@ -29,6 +29,7 @@ "skipBindingOnErrorCode": { "kind": "attribute", "displayName": "Skip Binding On Error Code", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to skip binding on output if there is a custom HTTP error code header. This allows to build custom error messages that do not bind to json \/ xml etc, as success messages otherwise will do." }, "clientRequestValidation": { "kind": "attribute", "displayName": "Client Request Validation", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable validation of the client request to check: 1) Content-Type header matches what the Rest DSL consumes; returns HTTP Status 415 if validation error. 2) Accept header matches what t [...] "enableCORS": { "kind": "attribute", "displayName": "Enable CORS", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to enable CORS headers in the HTTP response. The default value is false." }, + "inlineRoutes": { "kind": "attribute", "displayName": "Inline Routes", "label": "consumer", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Inline routes in rest-dsl which are linked using direct endpoints. By default, each service in Rest DSL is an individual route, meaning that you would have at least two routes per service (rest-dsl, and the route linked from res [...] "jsonDataFormat": { "kind": "attribute", "displayName": "Json Data Format", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of specific json data format to use. By default jackson will be used. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance." }, "xmlDataFormat": { "kind": "attribute", "displayName": "Xml Data Format", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of specific XML data format to use. By default jaxb will be used. Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance." }, "componentProperty": { "kind": "element", "displayName": "Component Property", "label": "advanced", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.rest.RestPropertyDefinition>", "deprecated": false, "autowired": false, "secret": false, "description": "Allows to configure as many additional properties for the rest component in use." }, diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java index bb946a0f164..94aa94f90f5 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java @@ -89,6 +89,9 @@ public class RestConfigurationDefinition { @Metadata(label = "consumer,advanced", javaType = "java.lang.Boolean", defaultValue = "false") private Boolean enableCORS; @XmlAttribute + @Metadata(label = "consumer", javaType = "java.lang.Boolean", defaultValue = "false") + private Boolean inlineRoutes; + @XmlAttribute @Metadata(label = "advanced") private String jsonDataFormat; @XmlAttribute @@ -330,6 +333,24 @@ public class RestConfigurationDefinition { this.enableCORS = enableCORS; } + public Boolean getInlineRoutes() { + return inlineRoutes; + } + + /** + * Inline routes in rest-dsl which are linked using direct endpoints. + * + * By default, each service in Rest DSL is an individual route, meaning that you would + * have at least two routes per service (rest-dsl, and the route linked from rest-dsl). + * Enabling this allows Camel to optimize and inline this as a single route, however + * this requires to use direct endpoints, which must be unique per service. + * + * This option is default <tt>false</tt>. + */ + public void setInlineRoutes(Boolean inlineRoutes) { + this.inlineRoutes = inlineRoutes; + } + public String getJsonDataFormat() { return jsonDataFormat; } @@ -611,6 +632,21 @@ public class RestConfigurationDefinition { return this; } + /** + * Inline routes in rest-dsl which are linked using direct endpoints. + * + * By default, each service in Rest DSL is an individual route, meaning that you would + * have at least two routes per service (rest-dsl, and the route linked from rest-dsl). + * Enabling this allows Camel to optimize and inline this as a single route, however + * this requires to use direct endpoints, which must be unique per service. + * + * This option is default <tt>false</tt>. + */ + public RestConfigurationDefinition inlineRoutes(boolean inlineRoutes) { + setInlineRoutes(inlineRoutes); + return this; + } + /** * To use a specific json data format * <p/> @@ -791,6 +827,9 @@ public class RestConfigurationDefinition { if (enableCORS != null) { target.setEnableCORS(enableCORS); } + if (inlineRoutes != null) { + target.setInlineRoutes(inlineRoutes); + } if (jsonDataFormat != null) { target.setJsonDataFormat(jsonDataFormat); } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java index facf13f6c53..2894f375357 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java @@ -333,10 +333,20 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> return this; } + public RestDefinition routeId(String routeId) { + if (getVerbs().isEmpty()) { + throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); + } + // add on last verb as that is how the Java DSL works + VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); + verb.setRouteId(routeId); + return this; + } + public RestDefinition deprecated() { if (!getVerbs().isEmpty()) { VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); - verb.deprecated(); + verb.setDeprecated("true"); } return this; @@ -680,6 +690,10 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> List<RouteDefinition> answer = new ArrayList<>(); RestConfiguration config = camelContext.getRestConfiguration(); + if (config.isInlineRoutes()) { + // sanity check this rest definition do not have duplicates linked routes via direct endpoints + validateUniqueDirects(); + } addRouteDefinition(camelContext, answer, config.getComponent(), config.getProducerComponent()); @@ -699,6 +713,21 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } } + protected void validateUniqueDirects() { + Set<String> directs = new HashSet<>(); + for (VerbDefinition verb : verbs) { + ToDefinition to = verb.getTo(); + if (to != null) { + String uri = to.getUri(); + if (uri.startsWith("direct:")) { + if (!directs.add(uri)) { + throw new IllegalArgumentException("Duplicate to in rest-dsl: " + uri); + } + } + } + } + } + protected String asTypeName(Class<?> classType) { // Workaround for https://issues.apache.org/jira/browse/CAMEL-15199 // @@ -769,6 +798,9 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> if (verb.getTo() == null) { throw new IllegalArgumentException("Rest service: " + verb + " must have to endpoint configured."); } + if (verb.getRouteId() != null) { + route.routeId(verb.getRouteId()); + } route.getOutputs().add(verb.getTo()); // add the binding diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/VerbDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/VerbDefinition.java index 9329ddb591e..667e447b5a3 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/VerbDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/VerbDefinition.java @@ -81,6 +81,8 @@ public abstract class VerbDefinition extends OptionalIdentifiedDefinition<VerbDe @XmlAttribute @Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue = "false") private String deprecated; + @XmlAttribute + private String routeId; @XmlElement(required = true) private ToDefinition to; @@ -110,6 +112,18 @@ public abstract class VerbDefinition extends OptionalIdentifiedDefinition<VerbDe return this; } + public String getRouteId() { + return routeId; + } + + /** + * Sets the id of the route + */ + public void setRouteId(String routeId) { + this.routeId = routeId; + } + + public List<ParamDefinition> getParams() { return params; } diff --git a/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestInlineRoutesTest.java b/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestInlineRoutesTest.java new file mode 100644 index 00000000000..f5eed728bb3 --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestInlineRoutesTest.java @@ -0,0 +1,69 @@ +/* + * 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; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.Registry; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class FromRestInlineRoutesTest extends ContextTestSupport { + + @Override + protected Registry createRegistry() throws Exception { + Registry jndi = super.createRegistry(); + jndi.bind("dummy-rest", new DummyRestConsumerFactory()); + return jndi; + } + + protected int getExpectedNumberOfRoutes() { + return 2; // inlined routes so there are only 2 + } + + @Test + public void testInlined() throws Exception { + assertEquals(getExpectedNumberOfRoutes(), context.getRoutes().size()); + + assertEquals(2, context.getRestDefinitions().size()); + assertEquals(2, context.getRouteDefinitions().size()); + + // the rest becomes routes and the input is a seda endpoint created by + // the DummyRestConsumerFactory + String out = template.requestBody("seda:get-say-hello", "Me", String.class); + assertEquals("Hello World", out); + String out2 = template.requestBody("seda:get-say-bye", "Me", String.class); + assertEquals("Bye World", out2); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + restConfiguration().host("localhost").inlineRoutes(true); + + rest("/say/hello").get().to("direct:hello"); + rest("/say/bye").get().to("direct:bye"); + + from("direct:hello").transform().constant("Hello World"); + from("direct:bye").transform().constant("Bye World"); + } + }; + } +} diff --git a/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestRouteIdTest.java b/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestRouteIdTest.java new file mode 100644 index 00000000000..dd36316200f --- /dev/null +++ b/core/camel-core/src/test/java/org/apache/camel/component/rest/FromRestRouteIdTest.java @@ -0,0 +1,64 @@ +/* + * 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; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.model.rest.CollectionFormat; +import org.apache.camel.model.rest.RestParamType; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class FromRestRouteIdTest extends FromRestGetTest { + + @Test + public void testFromRestModel() throws Exception { + super.testFromRestModel(); + // should have getSayByeRoute + RouteDefinition def = context.getRouteDefinition("getSayByeRoute"); + assertNotNull(def); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + restConfiguration().host("localhost"); + rest("/say/hello").get().to("direct:hello"); + + rest("/say/bye").get().consumes("application/json").param().type(RestParamType.header) + .description("header param description1").dataType("integer") + .allowableValues("1", "2", "3", "4").defaultValue("1").name("header_count").required(true).endParam() + .param().type(RestParamType.query) + .description("header param description2").dataType("string").allowableValues("a", "b", "c", "d") + .defaultValue("b").collectionFormat(CollectionFormat.multi) + .name("header_letter").required(false).endParam().responseMessage().code(300).message("test msg") + .responseModel(Integer.class).header("rate") + .description("Rate limit").dataType("integer").endHeader().endResponseMessage().responseMessage() + .code("error").message("does not work").endResponseMessage() + .routeId("getSayByeRoute") + .to("direct:bye").post().to("mock:update"); + + from("direct:hello").transform().constant("Hello World"); + + from("direct:bye").transform().constant("Bye World"); + } + }; + } +} diff --git a/core/camel-main/src/generated/java/org/apache/camel/main/RestConfigurationPropertiesConfigurer.java b/core/camel-main/src/generated/java/org/apache/camel/main/RestConfigurationPropertiesConfigurer.java index 25b9e827956..fbd8bc1b0bf 100644 --- a/core/camel-main/src/generated/java/org/apache/camel/main/RestConfigurationPropertiesConfigurer.java +++ b/core/camel-main/src/generated/java/org/apache/camel/main/RestConfigurationPropertiesConfigurer.java @@ -55,6 +55,8 @@ public class RestConfigurationPropertiesConfigurer extends org.apache.camel.supp case "Host": target.setHost(property(camelContext, java.lang.String.class, value)); return true; case "hostnameresolver": case "HostNameResolver": target.setHostNameResolver(property(camelContext, java.lang.String.class, value)); return true; + case "inlineroutes": + case "InlineRoutes": target.setInlineRoutes(property(camelContext, boolean.class, value)); return true; case "jsondataformat": case "JsonDataFormat": target.setJsonDataFormat(property(camelContext, java.lang.String.class, value)); return true; case "port": @@ -112,6 +114,8 @@ public class RestConfigurationPropertiesConfigurer extends org.apache.camel.supp case "Host": return java.lang.String.class; case "hostnameresolver": case "HostNameResolver": return java.lang.String.class; + case "inlineroutes": + case "InlineRoutes": return boolean.class; case "jsondataformat": case "JsonDataFormat": return java.lang.String.class; case "port": @@ -170,6 +174,8 @@ public class RestConfigurationPropertiesConfigurer extends org.apache.camel.supp case "Host": return target.getHost(); case "hostnameresolver": case "HostNameResolver": return target.getHostNameResolver(); + case "inlineroutes": + case "InlineRoutes": return target.isInlineRoutes(); case "jsondataformat": case "JsonDataFormat": return target.getJsonDataFormat(); case "port": diff --git a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json index efd1b33060a..da0c1336d03 100644 --- a/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json +++ b/core/camel-main/src/generated/resources/META-INF/camel-main-configuration-metadata.json @@ -191,6 +191,7 @@ { "name": "camel.rest.endpointProperties", "description": "Sets additional options on endpoint level", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "object", "javaType": "java.util.Map" }, { "name": "camel.rest.host", "description": "Sets the hostname to use by the REST consumer", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.rest.hostNameResolver", "description": "Sets the resolver to use for resolving hostname", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "object", "javaType": "org.apache.camel.spi.RestHostNameResolver", "defaultValue": "RestHostNameResolver.allLocalIp", "enum": [ "allLocalIp", "localIp", "localHostName" ] }, + { "name": "camel.rest.inlineRoutes", "description": "Inline routes in rest-dsl which are linked using direct endpoints. By default, each service in Rest DSL is an individual route, meaning that you would have at least two routes per service (rest-dsl, and the route linked from rest-dsl). Enabling this allows Camel to optimize and inline this as a single route, however this requires to use direct endpoints, which must be unique per service. This option is default false.", "sourceType" [...] { "name": "camel.rest.jsonDataFormat", "description": "Sets a custom json data format to be used Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance.", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "string", "javaType": "java.lang.String" }, { "name": "camel.rest.port", "description": "Sets the port to use by the REST consumer", "sourceType": "org.apache.camel.spi.RestConfiguration", "type": "integer", "javaType": "int" }, { "name": "camel.rest.producerApiDoc", "description": "Sets the location of the api document (swagger api) the REST producer will use to validate the REST uri and query parameters are valid accordingly to the api document. This requires adding camel-swagger-java to the classpath, and any miss configuration will let Camel fail on startup and report the error(s). The location of the api document is loaded from classpath by default, but you can use file: or http: to refer to resources t [...] diff --git a/core/camel-main/src/main/docs/main.adoc b/core/camel-main/src/main/docs/main.adoc index 7bc34ab33c3..6d9f53c533a 100644 --- a/core/camel-main/src/main/docs/main.adoc +++ b/core/camel-main/src/main/docs/main.adoc @@ -175,7 +175,7 @@ The camel.health supports 7 options, which are listed below. |=== === Camel Rest-DSL configurations -The camel.rest supports 25 options, which are listed below. +The camel.rest supports 26 options, which are listed below. [width="100%",cols="2,5,^1,2",options="header"] |=== @@ -197,6 +197,7 @@ The camel.rest supports 25 options, which are listed below. | *camel.rest.endpointProperties* | Sets additional options on endpoint level | | Map | *camel.rest.host* | Sets the hostname to use by the REST consumer | | String | *camel.rest.hostNameResolver* | Sets the resolver to use for resolving hostname | RestHostNameResolver.allLocalIp | RestHostNameResolver +| *camel.rest.inlineRoutes* | Inline routes in rest-dsl which are linked using direct endpoints. By default, each service in Rest DSL is an individual route, meaning that you would have at least two routes per service (rest-dsl, and the route linked from rest-dsl). Enabling this allows Camel to optimize and inline this as a single route, however this requires to use direct endpoints, which must be unique per service. This option is default false. | false | boolean | *camel.rest.jsonDataFormat* | Sets a custom json data format to be used Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance. | | String | *camel.rest.port* | Sets the port to use by the REST consumer | | int | *camel.rest.producerApiDoc* | Sets the location of the api document (swagger api) the REST producer will use to validate the REST uri and query parameters are valid accordingly to the api document. This requires adding camel-swagger-java to the classpath, and any miss configuration will let Camel fail on startup and report the error(s). The location of the api document is loaded from classpath by default, but you can use file: or http: to refer to resources to load from file or http ur [...] diff --git a/core/camel-main/src/main/java/org/apache/camel/main/RestConfigurationProperties.java b/core/camel-main/src/main/java/org/apache/camel/main/RestConfigurationProperties.java index 6b8af6b61c6..dca65a9e607 100644 --- a/core/camel-main/src/main/java/org/apache/camel/main/RestConfigurationProperties.java +++ b/core/camel-main/src/main/java/org/apache/camel/main/RestConfigurationProperties.java @@ -232,6 +232,21 @@ public class RestConfigurationProperties extends RestConfiguration implements Bo return this; } + /** + * Inline routes in rest-dsl which are linked using direct endpoints. + * + * By default, each service in Rest DSL is an individual route, meaning that you would + * have at least two routes per service (rest-dsl, and the route linked from rest-dsl). + * Enabling this allows Camel to optimize and inline this as a single route, however + * this requires to use direct endpoints, which must be unique per service. + * + * This option is default <tt>false</tt>. + */ + public RestConfigurationProperties withInlineRoutes(boolean inlineRoutes) { + setInlineRoutes(inlineRoutes); + return this; + } + /** * Name of specific json data format to use. By default jackson will be used. Important: This option is only for * setting a custom name of the data format, not to refer to an existing data format instance. diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java index 8eb536fb300..d0db623bb8e 100644 --- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java +++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java @@ -2903,6 +2903,7 @@ public class ModelParser extends BaseParser { case "outType": def.setOutType(val); break; case "path": def.setPath(val); break; case "produces": def.setProduces(val); break; + case "routeId": def.setRouteId(val); break; case "skipBindingOnErrorCode": def.setSkipBindingOnErrorCode(val); break; case "type": def.setType(val); break; default: return optionalIdentifiedDefinitionAttributeHandler().accept(def, key, val); @@ -3070,6 +3071,7 @@ public class ModelParser extends BaseParser { case "enableCORS": def.setEnableCORS(Boolean.valueOf(val)); break; case "host": def.setHost(val); break; case "hostNameResolver": def.setHostNameResolver(RestHostNameResolver.valueOf(val)); break; + case "inlineRoutes": def.setInlineRoutes(Boolean.valueOf(val)); break; case "jsonDataFormat": def.setJsonDataFormat(val); break; case "port": def.setPort(val); break; case "producerApiDoc": def.setProducerApiDoc(val); break; diff --git a/docs/user-manual/modules/ROOT/pages/rest-dsl.adoc b/docs/user-manual/modules/ROOT/pages/rest-dsl.adoc index 0c49ea6afcf..14a55dd23aa 100644 --- a/docs/user-manual/modules/ROOT/pages/rest-dsl.adoc +++ b/docs/user-manual/modules/ROOT/pages/rest-dsl.adoc @@ -204,7 +204,59 @@ metrics about the routes, such as number of message processed, and their performance statistics. There is also a Rest Registry JMX MBean that contains a registry of all -REST services which has been defined. +REST services which has been defined. + +== Inline Rest DSL as a single route + +Each of the rest services becomes a Camel route, and this means, that if the rest +service is calling another Camel route via `direct`, which is a very common practice. +This means that each rest service then becomes 2 routes. This can become harder to manage +if you have many rest services. + +When you use `direct` endpoints then you can enable Rest DSL to automatically _inline_ the direct +route in the rest route, meaning that there is only 1 route per rest service. + +To do this you *MUST* use `direct` endpoints, and each endpoint must be unique name per service. +And the option `inlineRoutes` must be enabled. + +For example in the Java DSL below we have enabled inline routes and each rest service +uses `direct` endpoints with unique names. + +[source,java] +---- +restConfiguration().inlineRoutes(true); + +rest("/customers/") + .get("/{id}").to("direct:customerDetail") + .get("/{id}/orders").to("direct:customerOrders") + .post("/neworder").to("direct:customerNewOrder"); +---- + +And in XML: + +[source,xml] +---- +<restConfiguration inlineRoutes="true"/> + +<rest> + <get uri="/customers/{id}"> + <to uri="direct:customerDetail"/> + </get> + <get uri="/customers/{id}/orders"> + <to uri="direct:customerOrders"/> + </get> + <post uri="/customers/neworder"> + <to uri="direct:customerNewOrder"/> + </post> +</rest> +---- + +If you use Camel Main / Spring Boot / Quarkus / or Camel JBang you can also enable this in `application.properties` such as: + +[source,properties] +---- +camel.rest.inline-routes = true +---- == Binding to POJOs using @@ -431,13 +483,12 @@ The Rest DSL supports the following options: |=== | Name | Description | Default | Type | *apiComponent* | Sets the name of the Camel component to use as the REST API (such as swagger or openapi) | | String -| *apiContextIdPattern* | Optional CamelContext id pattern to only allow Rest APIs from rest services within CamelContext's which name matches the pattern. The pattern #name# refers to the CamelContext name, to match on the current CamelContext only. For any other value, the pattern uses the rules from org.apache.camel.support.EndpointHelper#matchPattern(String,String) | | String | *apiContextPath* | Sets a leading API context-path the REST API services will be using. This can be used when using components such as camel-servlet where the deployed web application is deployed using a context-path. | | String | *apiHost* | To use a specific hostname for the API documentation (such as swagger or openapi) This can be used to override the generated host with this configured hostname | | String | *apiProperties* | Sets additional options on api level | | Map | *apiVendorExtension* | Whether vendor extension is enabled in the Rest APIs. If enabled then Camel will include additional information as vendor extension (eg keys starting with x-) such as route ids, class names etc. Not all 3rd party API gateways and tools supports vendor-extensions when importing your API docs. | false | boolean | *bindingMode* | Sets the binding mode to be used by the REST consumer | RestBindingMode.off | RestBindingMode -| *clientRequestValidation* | Whether to enable validation of the client request to check whether the Content-Type and Accept headers from the client is supported by the Rest-DSL configuration of its consumes/produces settings. This can be turned on, to enable this check. In case of validation error, then HTTP Status codes 415 or 406 is returned. The default value is false. | false | boolean +| *clientRequestValidation* | Whether to enable validation of the client request to check: 1) Content-Type header matches what the Rest DSL consumes; returns HTTP Status 415 if validation error. 2) Accept header matches what the Rest DSL produces; returns HTTP Status 406 if validation error. 3) Missing required data (query parameters, HTTP headers, body); returns HTTP Status 400 if validation error. 4) Parsing error of the message body (JSon, XML or Auto binding mode must be enabled); re [...] | *component* | Sets the name of the Camel component to use as the REST consumer | | String | *componentProperties* | Sets additional options on component level | | Map | *consumerProperties* | Sets additional options on consumer level | | Map @@ -448,6 +499,7 @@ The Rest DSL supports the following options: | *endpointProperties* | Sets additional options on endpoint level | | Map | *host* | Sets the hostname to use by the REST consumer | | String | *hostNameResolver* | Sets the resolver to use for resolving hostname | RestHostNameResolver.allLocalIp | RestHostNameResolver +| *inlineRoutes* | Inline routes in rest-dsl which are linked using direct endpoints. By default, each service in Rest DSL is an individual route, meaning that you would have at least two routes per service (rest-dsl, and the route linked from rest-dsl). Enabling this allows Camel to optimize and inline this as a single route, however this requires to use direct endpoints, which must be unique per service. This option is default false. | false | boolean | *jsonDataFormat* | Sets a custom json data format to be used Important: This option is only for setting a custom name of the data format, not to refer to an existing data format instance. | | String | *port* | Sets the port to use by the REST consumer | | int | *producerApiDoc* | Sets the location of the api document (swagger api) the REST producer will use to validate the REST uri and query parameters are valid accordingly to the api document. This requires adding camel-swagger-java to the classpath, and any miss configuration will let Camel fail on startup and report the error(s). The location of the api document is loaded from classpath by default, but you can use file: or http: to refer to resources to load from file or http url. | | String