You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by je...@apache.org on 2021/08/16 20:21:14 UTC

[camel] 02/02: CAMEL-16122: camel-graphql - Supply query via body or header.

This is an automated email from the ASF dual-hosted git repository.

jeremyross pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit ff3021530e337e2311a29eec27dddb3f98f37b7f
Author: Jeremy Ross <je...@gmail.com>
AuthorDate: Mon Aug 16 10:06:33 2021 -0500

    CAMEL-16122: camel-graphql - Supply query via body or header.
---
 .../camel/catalog/docs/graphql-component.adoc      | 23 +++++++++++++++--
 .../graphql/GraphqlEndpointConfigurer.java         |  6 +++++
 .../graphql/GraphqlEndpointUriFactory.java         | 11 ++++----
 .../apache/camel/component/graphql/graphql.json    |  1 +
 .../src/main/docs/graphql-component.adoc           | 23 +++++++++++++++--
 .../camel/component/graphql/GraphqlEndpoint.java   | 21 ++++++++++++++++
 .../camel/component/graphql/GraphqlProducer.java   | 15 ++++++++++-
 .../component/graphql/GraphqlComponentTest.java    | 29 ++++++++++++++++++++++
 .../dsl/GraphqlEndpointBuilderFactory.java         | 14 +++++++++++
 .../modules/ROOT/pages/graphql-component.adoc      | 23 +++++++++++++++--
 10 files changed, 154 insertions(+), 12 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
index 289f573..2cce5bd 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/docs/graphql-component.adoc
@@ -100,7 +100,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (11 parameters):
+=== Query Parameters (12 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -111,6 +111,7 @@ with the following path and query parameters:
 | *proxyHost* (producer) | The proxy host in the format hostname:port. |  | String
 | *query* (producer) | The query text. |  | String
 | *queryFile* (producer) | The query file name located in the classpath. |  | String
+| *queryHeader* (producer) | The name of a header containing the GraphQL query. |  | String
 | *variables* (producer) | The JsonObject instance containing the operation variables. |  | JsonObject
 | *variablesHeader* (producer) | The name of a header containing a JsonObject instance containing the operation variables. |  | String
 | *accessToken* (security) | The access token sent in the Authorization header. |  | String
@@ -123,7 +124,7 @@ with the following path and query parameters:
 
 == Message Body
 
-If the `variables` and `variablesHeader` parameters are not used and the IN body is a JsonObject instance, Camel will use it for the operation's variables. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will add the HTTP response headers as well to the OUT message headers.
+If the `variables` and `variablesHeader` parameters are not set and the IN body is a JsonObject instance, Camel will use it for the operation's variables. If the `query` and `queryFile` parameters are not set and the IN body is a String, Camel will use it as the query. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will ad [...]
 
 == Examples
 
@@ -137,6 +138,24 @@ from("direct:start")
     .to("graphql://http://example.com/graphql?query={books{id name}}")
 ----
 
+The body can also be used for the query:
+
+[source,java]
+----
+from("direct:start")
+    .setBody(constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql")
+----
+
+The query can come from a header also:
+
+[source,java]
+----
+from("direct:start")
+    .setHeader("myQuery", constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql?queryHeader=myQuery")
+----
+
 More complex queries can be stored in a file and referenced in the URI:
 
 booksQuery.graphql file:
diff --git a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointConfigurer.java b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointConfigurer.java
index 13d6e61..c804a93 100644
--- a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointConfigurer.java
+++ b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointConfigurer.java
@@ -35,6 +35,8 @@ public class GraphqlEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "query": target.setQuery(property(camelContext, java.lang.String.class, value)); return true;
         case "queryfile":
         case "queryFile": target.setQueryFile(property(camelContext, java.lang.String.class, value)); return true;
+        case "queryheader":
+        case "queryHeader": target.setQueryHeader(property(camelContext, java.lang.String.class, value)); return true;
         case "username": target.setUsername(property(camelContext, java.lang.String.class, value)); return true;
         case "variables": target.setVariables(property(camelContext, org.apache.camel.util.json.JsonObject.class, value)); return true;
         case "variablesheader":
@@ -60,6 +62,8 @@ public class GraphqlEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "query": return java.lang.String.class;
         case "queryfile":
         case "queryFile": return java.lang.String.class;
+        case "queryheader":
+        case "queryHeader": return java.lang.String.class;
         case "username": return java.lang.String.class;
         case "variables": return org.apache.camel.util.json.JsonObject.class;
         case "variablesheader":
@@ -86,6 +90,8 @@ public class GraphqlEndpointConfigurer extends PropertyConfigurerSupport impleme
         case "query": return target.getQuery();
         case "queryfile":
         case "queryFile": return target.getQueryFile();
+        case "queryheader":
+        case "queryHeader": return target.getQueryHeader();
         case "username": return target.getUsername();
         case "variables": return target.getVariables();
         case "variablesheader":
diff --git a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointUriFactory.java b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointUriFactory.java
index b7d8a1c..57312bf 100644
--- a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointUriFactory.java
+++ b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlEndpointUriFactory.java
@@ -20,18 +20,19 @@ public class GraphqlEndpointUriFactory extends org.apache.camel.support.componen
     private static final Set<String> PROPERTY_NAMES;
     private static final Set<String> SECRET_PROPERTY_NAMES;
     static {
-        Set<String> props = new HashSet<>(12);
-        props.add("lazyStartProducer");
+        Set<String> props = new HashSet<>(13);
+        props.add("queryHeader");
         props.add("queryFile");
         props.add("variables");
-        props.add("password");
-        props.add("jwtAuthorizationType");
-        props.add("httpUri");
         props.add("query");
         props.add("variablesHeader");
         props.add("operationName");
         props.add("accessToken");
         props.add("proxyHost");
+        props.add("lazyStartProducer");
+        props.add("password");
+        props.add("jwtAuthorizationType");
+        props.add("httpUri");
         props.add("username");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         Set<String> secretProps = new HashSet<>(3);
diff --git a/components/camel-graphql/src/generated/resources/org/apache/camel/component/graphql/graphql.json b/components/camel-graphql/src/generated/resources/org/apache/camel/component/graphql/graphql.json
index 93bff64..89b6011 100644
--- a/components/camel-graphql/src/generated/resources/org/apache/camel/component/graphql/graphql.json
+++ b/components/camel-graphql/src/generated/resources/org/apache/camel/component/graphql/graphql.json
@@ -32,6 +32,7 @@
     "proxyHost": { "kind": "parameter", "displayName": "Proxy Host", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The proxy host in the format hostname:port." },
     "query": { "kind": "parameter", "displayName": "Query", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The query text." },
     "queryFile": { "kind": "parameter", "displayName": "Query File", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The query file name located in the classpath." },
+    "queryHeader": { "kind": "parameter", "displayName": "Query Header", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The name of a header containing the GraphQL query." },
     "variables": { "kind": "parameter", "displayName": "Variables", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.util.json.JsonObject", "deprecated": false, "autowired": false, "secret": false, "description": "The JsonObject instance containing the operation variables." },
     "variablesHeader": { "kind": "parameter", "displayName": "Variables Header", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The name of a header containing a JsonObject instance containing the operation variables." },
     "accessToken": { "kind": "parameter", "displayName": "Access Token", "group": "security", "label": "security", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": true, "description": "The access token sent in the Authorization header." },
diff --git a/components/camel-graphql/src/main/docs/graphql-component.adoc b/components/camel-graphql/src/main/docs/graphql-component.adoc
index 289f573..2cce5bd 100644
--- a/components/camel-graphql/src/main/docs/graphql-component.adoc
+++ b/components/camel-graphql/src/main/docs/graphql-component.adoc
@@ -100,7 +100,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (11 parameters):
+=== Query Parameters (12 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -111,6 +111,7 @@ with the following path and query parameters:
 | *proxyHost* (producer) | The proxy host in the format hostname:port. |  | String
 | *query* (producer) | The query text. |  | String
 | *queryFile* (producer) | The query file name located in the classpath. |  | String
+| *queryHeader* (producer) | The name of a header containing the GraphQL query. |  | String
 | *variables* (producer) | The JsonObject instance containing the operation variables. |  | JsonObject
 | *variablesHeader* (producer) | The name of a header containing a JsonObject instance containing the operation variables. |  | String
 | *accessToken* (security) | The access token sent in the Authorization header. |  | String
@@ -123,7 +124,7 @@ with the following path and query parameters:
 
 == Message Body
 
-If the `variables` and `variablesHeader` parameters are not used and the IN body is a JsonObject instance, Camel will use it for the operation's variables. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will add the HTTP response headers as well to the OUT message headers.
+If the `variables` and `variablesHeader` parameters are not set and the IN body is a JsonObject instance, Camel will use it for the operation's variables. If the `query` and `queryFile` parameters are not set and the IN body is a String, Camel will use it as the query. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will ad [...]
 
 == Examples
 
@@ -137,6 +138,24 @@ from("direct:start")
     .to("graphql://http://example.com/graphql?query={books{id name}}")
 ----
 
+The body can also be used for the query:
+
+[source,java]
+----
+from("direct:start")
+    .setBody(constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql")
+----
+
+The query can come from a header also:
+
+[source,java]
+----
+from("direct:start")
+    .setHeader("myQuery", constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql?queryHeader=myQuery")
+----
+
 More complex queries can be stored in a file and referenced in the URI:
 
 booksQuery.graphql file:
diff --git a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
index d4b79b9..54bcc28 100644
--- a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
+++ b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlEndpoint.java
@@ -76,6 +76,8 @@ public class GraphqlEndpoint extends DefaultEndpoint {
     private JsonObject variables;
     @UriParam
     private String variablesHeader;
+    @UriParam
+    private String queryHeader;
 
     private CloseableHttpClient httpClient;
 
@@ -256,4 +258,23 @@ public class GraphqlEndpoint extends DefaultEndpoint {
     public void setVariablesHeader(String variablesHeader) {
         this.variablesHeader = variablesHeader;
     }
+
+    public String getQueryHeader() {
+        return queryHeader;
+    }
+
+    /**
+     * The name of a header containing the GraphQL query.
+     */
+    public void setQueryHeader(String queryHeader) {
+        this.queryHeader = queryHeader;
+    }
+
+    public CloseableHttpClient getHttpClient() {
+        return httpClient;
+    }
+
+    public void setHttpClient(CloseableHttpClient httpClient) {
+        this.httpClient = httpClient;
+    }
 }
diff --git a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlProducer.java b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlProducer.java
index 4b38424..9478bab 100644
--- a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlProducer.java
+++ b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlProducer.java
@@ -20,6 +20,7 @@ import java.net.URI;
 
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.support.DefaultAsyncProducer;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.http.HttpEntity;
@@ -46,7 +47,7 @@ public class GraphqlProducer extends DefaultAsyncProducer {
         try {
             CloseableHttpClient httpClient = getEndpoint().getHttpclient();
             URI httpUri = getEndpoint().getHttpUri();
-            String requestBody = buildRequestBody(getEndpoint().getQuery(), getEndpoint().getOperationName(),
+            String requestBody = buildRequestBody(getQuery(exchange), getEndpoint().getOperationName(),
                     getVariables(exchange));
             HttpEntity requestEntity = new StringEntity(requestBody, ContentType.create("application/json", "UTF-8"));
 
@@ -75,6 +76,18 @@ public class GraphqlProducer extends DefaultAsyncProducer {
         return jsonObject.toJson();
     }
 
+    private String getQuery(Exchange exchange) throws InvalidPayloadException {
+        String query = null;
+        if (getEndpoint().getQuery() != null) {
+            query = getEndpoint().getQuery();
+        } else if (getEndpoint().getQueryHeader() != null) {
+            query = exchange.getIn().getHeader(getEndpoint().getQueryHeader(), String.class);
+        } else {
+            query = exchange.getIn().getMandatoryBody(String.class);
+        }
+        return query;
+    }
+
     private JsonObject getVariables(Exchange exchange) {
         JsonObject variables = null;
         if (getEndpoint().getVariables() != null) {
diff --git a/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/GraphqlComponentTest.java b/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/GraphqlComponentTest.java
index b2cd7b3..356f178 100644
--- a/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/GraphqlComponentTest.java
+++ b/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/GraphqlComponentTest.java
@@ -103,6 +103,15 @@ public class GraphqlComponentTest extends CamelTestSupport {
                         .to("graphql://http://localhost:" + server.getPort()
                             + "/graphql?query={books{id name}}&variablesHeader=bookByIdQueryVariables")
                         .to("mock:result");
+                from("direct:start6")
+                        .to("graphql://http://localhost:" + server.getPort()
+                            + "/graphql")
+                        .to("mock:result");
+                from("direct:start7")
+                        .setHeader("myQuery", constant("{books{id name}}"))
+                        .to("graphql://http://localhost:" + server.getPort()
+                            + "/graphql?queryHeader=myQuery")
+                        .to("mock:result");
             }
         };
     }
@@ -118,6 +127,26 @@ public class GraphqlComponentTest extends CamelTestSupport {
     }
 
     @Test
+    public void booksQueryWithStaticQueryInBody() throws Exception {
+        result.expectedMessageCount(1);
+        result.expectedBodiesReceived(booksQueryResult);
+
+        template.sendBody("direct:start6", "{books{id name}}");
+
+        result.assertIsSatisfied();
+    }
+
+    @Test
+    public void booksQueryWithStaticQueryInHeader() throws Exception {
+        result.expectedMessageCount(1);
+        result.expectedBodiesReceived(booksQueryResult);
+
+        template.sendBody("direct:start7", "");
+
+        result.assertIsSatisfied();
+    }
+
+    @Test
     public void booksQueryWithQueryFile() throws Exception {
         result.expectedMessageCount(1);
         result.expectedBodiesReceived(booksQueryResult);
diff --git a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
index ef65cac..9866d90 100644
--- a/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
@@ -140,6 +140,20 @@ public interface GraphqlEndpointBuilderFactory {
             return this;
         }
         /**
+         * The name of a header containing the GraphQL query.
+         * 
+         * The option is a: &lt;code&gt;java.lang.String&lt;/code&gt; type.
+         * 
+         * Group: producer
+         * 
+         * @param queryHeader the value to set
+         * @return the dsl builder
+         */
+        default GraphqlEndpointBuilder queryHeader(String queryHeader) {
+            doSetProperty("queryHeader", queryHeader);
+            return this;
+        }
+        /**
          * The JsonObject instance containing the operation variables.
          * 
          * The option is a:
diff --git a/docs/components/modules/ROOT/pages/graphql-component.adoc b/docs/components/modules/ROOT/pages/graphql-component.adoc
index d88fd05..1aec52f 100644
--- a/docs/components/modules/ROOT/pages/graphql-component.adoc
+++ b/docs/components/modules/ROOT/pages/graphql-component.adoc
@@ -102,7 +102,7 @@ with the following path and query parameters:
 |===
 
 
-=== Query Parameters (11 parameters):
+=== Query Parameters (12 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -113,6 +113,7 @@ with the following path and query parameters:
 | *proxyHost* (producer) | The proxy host in the format hostname:port. |  | String
 | *query* (producer) | The query text. |  | String
 | *queryFile* (producer) | The query file name located in the classpath. |  | String
+| *queryHeader* (producer) | The name of a header containing the GraphQL query. |  | String
 | *variables* (producer) | The JsonObject instance containing the operation variables. |  | JsonObject
 | *variablesHeader* (producer) | The name of a header containing a JsonObject instance containing the operation variables. |  | String
 | *accessToken* (security) | The access token sent in the Authorization header. |  | String
@@ -125,7 +126,7 @@ with the following path and query parameters:
 
 == Message Body
 
-If the `variables` and `variablesHeader` parameters are not used and the IN body is a JsonObject instance, Camel will use it for the operation's variables. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will add the HTTP response headers as well to the OUT message headers.
+If the `variables` and `variablesHeader` parameters are not set and the IN body is a JsonObject instance, Camel will use it for the operation's variables. If the `query` and `queryFile` parameters are not set and the IN body is a String, Camel will use it as the query. Camel will store the GraphQL response from the external server on the OUT message body. All headers from the IN message will be copied to the OUT message, so headers are preserved during routing. Additionally Camel will ad [...]
 
 == Examples
 
@@ -139,6 +140,24 @@ from("direct:start")
     .to("graphql://http://example.com/graphql?query={books{id name}}")
 ----
 
+The body can also be used for the query:
+
+[source,java]
+----
+from("direct:start")
+    .setBody(constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql")
+----
+
+The query can come from a header also:
+
+[source,java]
+----
+from("direct:start")
+    .setHeader("myQuery", constant("{books{id name}}"))
+    .to("graphql://http://example.com/graphql?queryHeader=myQuery")
+----
+
 More complex queries can be stored in a file and referenced in the URI:
 
 booksQuery.graphql file: