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 d1d2bec0a0d1 CAMEL-22561: camel-graphq - Add support for header filter 
strategy to include HTTP headers like camel-http and use more of same logic as 
camel-http. (#19592)
d1d2bec0a0d1 is described below

commit d1d2bec0a0d15ccbf3a3339db9ac2bc33ee87032
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Oct 16 15:04:04 2025 +0200

    CAMEL-22561: camel-graphq - Add support for header filter strategy to 
include HTTP headers like camel-http and use more of same logic as camel-http. 
(#19592)
---
 .../apache/camel/catalog/components/graphql.json   |  34 ++--
 components/camel-graphql/pom.xml                   |   4 +
 .../graphql/GraphqlComponentConfigurer.java        |  12 ++
 .../graphql/GraphqlEndpointConfigurer.java         |  12 ++
 .../graphql/GraphqlEndpointUriFactory.java         |   4 +-
 .../apache/camel/component/graphql/graphql.json    |  34 ++--
 .../camel/component/graphql/GraphqlComponent.java  |  16 +-
 .../camel/component/graphql/GraphqlEndpoint.java   |  32 ++++
 .../camel/component/graphql/GraphqlProducer.java   | 198 ++++++++++++++++++++-
 .../component/graphql/GraphqlComponentTest.java    |  36 +++-
 .../component/graphql/server/GraphqlServer.java    |  14 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_16.adoc    |   7 +
 .../dsl/GraphqlComponentBuilderFactory.java        |  39 ++++
 .../dsl/GraphqlEndpointBuilderFactory.java         |  66 +++++++
 14 files changed, 468 insertions(+), 40 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
index bf28673012e1..1070c3482236 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/graphql.json
@@ -25,23 +25,27 @@
   },
   "componentProperties": {
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
-    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
-    "httpClient": { "index": 2, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." }
+    "throwExceptionOnFailure": { "index": 1, "kind": "property", 
"displayName": "Throw Exception On Failure", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Option to disable throwing the HttpOperationFailedException in 
case of failed responses from the remote server. This allows you to get all 
responses regardless of the HTTP status code." },
+    "autowiredEnabled": { "index": 2, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "httpClient": { "index": 3, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
+    "headerFilterStrategy": { "index": 4, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "filter", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The GraphQL server URI." },
-    "operationName": { "index": 1, "kind": "parameter", "displayName": 
"Operation Name", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "The query or mutation name." },
-    "proxyHost": { "index": 2, "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": { "index": 3, "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": { "index": 4, "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 
(or use file: to load from file system)." },
-    "queryHeader": { "index": 5, "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": { "index": 6, "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": { "index": 7, "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." },
-    "lazyStartProducer": { "index": 8, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
-    "httpClient": { "index": 9, "kind": "parameter", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
-    "accessToken": { "index": 10, "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." },
-    "jwtAuthorizationType": { "index": 11, "kind": "parameter", "displayName": 
"Jwt Authorization Type", "group": "security", "label": "security", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "Bearer", "description": 
"The JWT Authorization type. Default is Bearer." },
-    "password": { "index": 12, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The password for Basic authentication." },
-    "username": { "index": 13, "kind": "parameter", "displayName": "Username", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The username for Basic authentication." }
+    "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "common (advanced)", "label": 
"common,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "operationName": { "index": 2, "kind": "parameter", "displayName": 
"Operation Name", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "The query or mutation name." },
+    "proxyHost": { "index": 3, "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": { "index": 4, "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": { "index": 5, "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 
(or use file: to load from file system)." },
+    "queryHeader": { "index": 6, "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." },
+    "throwExceptionOnFailure": { "index": 7, "kind": "parameter", 
"displayName": "Throw Exception On Failure", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Option to disable throwing the HttpOperationFailedException in 
case of failed responses from the remote server. This allows you to get all 
responses regardless of the HTTP status code." },
+    "variables": { "index": 8, "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": { "index": 9, "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." },
+    "lazyStartProducer": { "index": 10, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "httpClient": { "index": 11, "kind": "parameter", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
+    "accessToken": { "index": 12, "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." },
+    "jwtAuthorizationType": { "index": 13, "kind": "parameter", "displayName": 
"Jwt Authorization Type", "group": "security", "label": "security", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "Bearer", "description": 
"The JWT Authorization type. Default is Bearer." },
+    "password": { "index": 14, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The password for Basic authentication." },
+    "username": { "index": 15, "kind": "parameter", "displayName": "Username", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The username for Basic authentication." }
   }
 }
diff --git a/components/camel-graphql/pom.xml b/components/camel-graphql/pom.xml
index dcc0015ee79d..a8bdebabedfa 100644
--- a/components/camel-graphql/pom.xml
+++ b/components/camel-graphql/pom.xml
@@ -37,6 +37,10 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-support</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-http-base</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-util-json</artifactId>
diff --git 
a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlComponentConfigurer.java
 
b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlComponentConfigurer.java
index f706783f4d41..1cdb13791e0a 100644
--- 
a/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlComponentConfigurer.java
+++ 
b/components/camel-graphql/src/generated/java/org/apache/camel/component/graphql/GraphqlComponentConfigurer.java
@@ -25,10 +25,14 @@ public class GraphqlComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": 
target.setAutowiredEnabled(property(camelContext, boolean.class, value)); 
return true;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": 
target.setHeaderFilterStrategy(property(camelContext, 
org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
         case "httpclient":
         case "httpClient": target.setHttpClient(property(camelContext, 
org.apache.hc.client5.http.classic.HttpClient.class, value)); return true;
         case "lazystartproducer":
         case "lazyStartProducer": 
target.setLazyStartProducer(property(camelContext, boolean.class, value)); 
return true;
+        case "throwexceptiononfailure":
+        case "throwExceptionOnFailure": 
target.setThrowExceptionOnFailure(property(camelContext, boolean.class, 
value)); return true;
         default: return false;
         }
     }
@@ -38,10 +42,14 @@ public class GraphqlComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": return boolean.class;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return 
org.apache.camel.spi.HeaderFilterStrategy.class;
         case "httpclient":
         case "httpClient": return 
org.apache.hc.client5.http.classic.HttpClient.class;
         case "lazystartproducer":
         case "lazyStartProducer": return boolean.class;
+        case "throwexceptiononfailure":
+        case "throwExceptionOnFailure": return boolean.class;
         default: return null;
         }
     }
@@ -52,10 +60,14 @@ public class GraphqlComponentConfigurer extends 
PropertyConfigurerSupport implem
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "autowiredenabled":
         case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return target.getHeaderFilterStrategy();
         case "httpclient":
         case "httpClient": return target.getHttpClient();
         case "lazystartproducer":
         case "lazyStartProducer": return target.isLazyStartProducer();
+        case "throwexceptiononfailure":
+        case "throwExceptionOnFailure": return 
target.isThrowExceptionOnFailure();
         default: return null;
         }
     }
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 29ac803713ac..07c0356d90e2 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
@@ -25,6 +25,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "accesstoken":
         case "accessToken": target.setAccessToken(property(camelContext, 
java.lang.String.class, value)); return true;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": 
target.setHeaderFilterStrategy(property(camelContext, 
org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
         case "httpclient":
         case "httpClient": target.setHttpClient(property(camelContext, 
org.apache.hc.client5.http.classic.HttpClient.class, value)); return true;
         case "jwtauthorizationtype":
@@ -41,6 +43,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         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 "throwexceptiononfailure":
+        case "throwExceptionOnFailure": 
target.setThrowExceptionOnFailure(property(camelContext, boolean.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":
@@ -54,6 +58,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "accesstoken":
         case "accessToken": return java.lang.String.class;
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return 
org.apache.camel.spi.HeaderFilterStrategy.class;
         case "httpclient":
         case "httpClient": return 
org.apache.hc.client5.http.classic.HttpClient.class;
         case "jwtauthorizationtype":
@@ -70,6 +76,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         case "queryFile": return java.lang.String.class;
         case "queryheader":
         case "queryHeader": return java.lang.String.class;
+        case "throwexceptiononfailure":
+        case "throwExceptionOnFailure": return boolean.class;
         case "username": return java.lang.String.class;
         case "variables": return org.apache.camel.util.json.JsonObject.class;
         case "variablesheader":
@@ -84,6 +92,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         switch (ignoreCase ? name.toLowerCase() : name) {
         case "accesstoken":
         case "accessToken": return target.getAccessToken();
+        case "headerfilterstrategy":
+        case "headerFilterStrategy": return target.getHeaderFilterStrategy();
         case "httpclient":
         case "httpClient": return target.getHttpClient();
         case "jwtauthorizationtype":
@@ -100,6 +110,8 @@ public class GraphqlEndpointConfigurer extends 
PropertyConfigurerSupport impleme
         case "queryFile": return target.getQueryFile();
         case "queryheader":
         case "queryHeader": return target.getQueryHeader();
+        case "throwexceptiononfailure":
+        case "throwExceptionOnFailure": return 
target.isThrowExceptionOnFailure();
         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 7e1696a1a13d..bf37617172ec 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
@@ -23,8 +23,9 @@ public class GraphqlEndpointUriFactory extends 
org.apache.camel.support.componen
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(14);
+        Set<String> props = new HashSet<>(16);
         props.add("accessToken");
+        props.add("headerFilterStrategy");
         props.add("httpClient");
         props.add("httpUri");
         props.add("jwtAuthorizationType");
@@ -35,6 +36,7 @@ public class GraphqlEndpointUriFactory extends 
org.apache.camel.support.componen
         props.add("query");
         props.add("queryFile");
         props.add("queryHeader");
+        props.add("throwExceptionOnFailure");
         props.add("username");
         props.add("variables");
         props.add("variablesHeader");
diff --git 
a/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
 
b/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
index bf28673012e1..1070c3482236 100644
--- 
a/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
+++ 
b/components/camel-graphql/src/generated/resources/META-INF/org/apache/camel/component/graphql/graphql.json
@@ -25,23 +25,27 @@
   },
   "componentProperties": {
     "lazyStartProducer": { "index": 0, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
-    "autowiredEnabled": { "index": 1, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
-    "httpClient": { "index": 2, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." }
+    "throwExceptionOnFailure": { "index": 1, "kind": "property", 
"displayName": "Throw Exception On Failure", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Option to disable throwing the HttpOperationFailedException in 
case of failed responses from the remote server. This allows you to get all 
responses regardless of the HTTP status code." },
+    "autowiredEnabled": { "index": 2, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "httpClient": { "index": 3, "kind": "property", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
+    "headerFilterStrategy": { "index": 4, "kind": "property", "displayName": 
"Header Filter Strategy", "group": "filter", "label": "filter", "required": 
false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom 
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel 
message." }
   },
   "properties": {
     "httpUri": { "index": 0, "kind": "path", "displayName": "Http Uri", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.net.URI", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The GraphQL server URI." },
-    "operationName": { "index": 1, "kind": "parameter", "displayName": 
"Operation Name", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "The query or mutation name." },
-    "proxyHost": { "index": 2, "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": { "index": 3, "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": { "index": 4, "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 
(or use file: to load from file system)." },
-    "queryHeader": { "index": 5, "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": { "index": 6, "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": { "index": 7, "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." },
-    "lazyStartProducer": { "index": 8, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produc [...]
-    "httpClient": { "index": 9, "kind": "parameter", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
-    "accessToken": { "index": 10, "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." },
-    "jwtAuthorizationType": { "index": 11, "kind": "parameter", "displayName": 
"Jwt Authorization Type", "group": "security", "label": "security", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "Bearer", "description": 
"The JWT Authorization type. Default is Bearer." },
-    "password": { "index": 12, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The password for Basic authentication." },
-    "username": { "index": 13, "kind": "parameter", "displayName": "Username", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The username for Basic authentication." }
+    "headerFilterStrategy": { "index": 1, "kind": "parameter", "displayName": 
"Header Filter Strategy", "group": "common (advanced)", "label": 
"common,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired": 
false, "secret": false, "description": "To use a custom HeaderFilterStrategy to 
filter header to and from Camel message." },
+    "operationName": { "index": 2, "kind": "parameter", "displayName": 
"Operation Name", "group": "producer", "label": "", "required": false, "type": 
"string", "javaType": "java.lang.String", "deprecated": false, "autowired": 
false, "secret": false, "description": "The query or mutation name." },
+    "proxyHost": { "index": 3, "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": { "index": 4, "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": { "index": 5, "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 
(or use file: to load from file system)." },
+    "queryHeader": { "index": 6, "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." },
+    "throwExceptionOnFailure": { "index": 7, "kind": "parameter", 
"displayName": "Throw Exception On Failure", "group": "producer", "label": 
"producer", "required": false, "type": "boolean", "javaType": "boolean", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true, 
"description": "Option to disable throwing the HttpOperationFailedException in 
case of failed responses from the remote server. This allows you to get all 
responses regardless of the HTTP status code." },
+    "variables": { "index": 8, "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": { "index": 9, "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." },
+    "lazyStartProducer": { "index": 10, "kind": "parameter", "displayName": 
"Lazy Start Producer", "group": "producer (advanced)", "label": 
"producer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Whether the producer should be started 
lazy (on the first message). By starting lazy you can use this to allow 
CamelContext and routes to startup in situations where a produ [...]
+    "httpClient": { "index": 11, "kind": "parameter", "displayName": "Http 
Client", "group": "advanced", "label": "advanced", "required": false, "type": 
"object", "javaType": "org.apache.hc.client5.http.classic.HttpClient", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
use a custom pre-existing Http Client. Beware that when using this, then other 
configurations such as proxy, access token, is not applied and all this must be 
pre-configured on the Http Client." },
+    "accessToken": { "index": 12, "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." },
+    "jwtAuthorizationType": { "index": 13, "kind": "parameter", "displayName": 
"Jwt Authorization Type", "group": "security", "label": "security", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "Bearer", "description": 
"The JWT Authorization type. Default is Bearer." },
+    "password": { "index": 14, "kind": "parameter", "displayName": "Password", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The password for Basic authentication." },
+    "username": { "index": 15, "kind": "parameter", "displayName": "Username", 
"group": "security", "label": "security", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "description": "The username for Basic authentication." }
   }
 }
diff --git 
a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlComponent.java
 
b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlComponent.java
index 5fdb1e1b643b..5bfe7605e873 100644
--- 
a/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlComponent.java
+++ 
b/components/camel-graphql/src/main/java/org/apache/camel/component/graphql/GraphqlComponent.java
@@ -22,20 +22,25 @@ import java.util.Map;
 import org.apache.camel.Endpoint;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.annotations.Component;
-import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.support.HeaderFilterStrategyComponent;
 import org.apache.camel.util.URISupport;
 import org.apache.hc.client5.http.classic.HttpClient;
 
 @Component("graphql")
-public class GraphqlComponent extends DefaultComponent {
+public class GraphqlComponent extends HeaderFilterStrategyComponent {
 
     @Metadata(label = "advanced")
     private HttpClient httpClient;
+    @Metadata(label = "producer", defaultValue = "true",
+              description = "Option to disable throwing the 
HttpOperationFailedException in case of failed responses from the remote 
server. This allows you to get all responses regardless of the HTTP status 
code.")
+    private boolean throwExceptionOnFailure = true;
 
     @Override
     protected Endpoint createEndpoint(String uri, String remaining, 
Map<String, Object> parameters) throws Exception {
         GraphqlEndpoint endpoint = new GraphqlEndpoint(uri, this);
+        endpoint.setHeaderFilterStrategy(getHeaderFilterStrategy());
         endpoint.setHttpClient(httpClient);
+        endpoint.setThrowExceptionOnFailure(throwExceptionOnFailure);
         endpoint.setHttpUri(new URI(remaining));
         setProperties(endpoint, parameters);
         return endpoint;
@@ -63,4 +68,11 @@ public class GraphqlComponent extends DefaultComponent {
         this.httpClient = httpClient;
     }
 
+    public boolean isThrowExceptionOnFailure() {
+        return throwExceptionOnFailure;
+    }
+
+    public void setThrowExceptionOnFailure(boolean throwExceptionOnFailure) {
+        this.throwExceptionOnFailure = throwExceptionOnFailure;
+    }
 }
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 51f7ae915233..f9e14e4513ac 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
@@ -28,7 +28,9 @@ import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
 import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.http.base.HttpHeaderFilterStrategy;
 import org.apache.camel.spi.EndpointServiceLocation;
+import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -85,6 +87,12 @@ public class GraphqlEndpoint extends DefaultEndpoint 
implements EndpointServiceL
     private String queryHeader;
     @UriParam(label = "advanced")
     private HttpClient httpClient;
+    @UriParam(label = "producer", defaultValue = "true",
+              description = "Option to disable throwing the 
HttpOperationFailedException in case of failed responses from the remote 
server. This allows you to get all responses regardless of the HTTP status 
code.")
+    private boolean throwExceptionOnFailure = true;
+    @UriParam(label = "common,advanced",
+              description = "To use a custom HeaderFilterStrategy to filter 
header to and from Camel message.")
+    private HeaderFilterStrategy headerFilterStrategy;
 
     public GraphqlEndpoint(String uri, Component component) {
         super(uri, component);
@@ -106,6 +114,14 @@ public class GraphqlEndpoint extends DefaultEndpoint 
implements EndpointServiceL
         return null;
     }
 
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        if (headerFilterStrategy == null) {
+            headerFilterStrategy = new HttpHeaderFilterStrategy();
+        }
+    }
+
     @Override
     public String getServiceProtocol() {
         return "rest";
@@ -302,6 +318,22 @@ public class GraphqlEndpoint extends DefaultEndpoint 
implements EndpointServiceL
         this.httpClient = httpClient;
     }
 
+    public boolean isThrowExceptionOnFailure() {
+        return throwExceptionOnFailure;
+    }
+
+    public void setThrowExceptionOnFailure(boolean throwExceptionOnFailure) {
+        this.throwExceptionOnFailure = throwExceptionOnFailure;
+    }
+
+    public HeaderFilterStrategy getHeaderFilterStrategy() {
+        return headerFilterStrategy;
+    }
+
+    public void setHeaderFilterStrategy(HeaderFilterStrategy 
headerFilterStrategy) {
+        this.headerFilterStrategy = headerFilterStrategy;
+    }
+
     @Override
     public boolean isLenientProperties() {
         return true;
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 aa607339bab2..71134975544f 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
@@ -16,32 +16,57 @@
  */
 package org.apache.camel.component.graphql;
 
+import java.io.IOException;
 import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.camel.AsyncCallback;
 import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePropertyKey;
 import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.http.base.HttpHelper;
+import org.apache.camel.http.base.HttpOperationFailedException;
+import org.apache.camel.spi.HeaderFilterStrategy;
 import org.apache.camel.support.DefaultAsyncProducer;
+import org.apache.camel.support.ObjectHelper;
+import org.apache.camel.support.http.HttpUtil;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.json.JsonObject;
 import org.apache.hc.client5.http.classic.HttpClient;
 import org.apache.hc.client5.http.classic.methods.HttpPost;
+import org.apache.hc.client5.http.classic.methods.HttpUriRequest;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.core5.http.ClassicHttpResponse;
 import org.apache.hc.core5.http.ContentType;
+import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.ParseException;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 import org.apache.hc.core5.http.io.entity.StringEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class GraphqlProducer extends DefaultAsyncProducer {
 
-    public GraphqlProducer(GraphqlEndpoint endpoint) {
-        super(endpoint);
-    }
+    private static final Logger LOG = 
LoggerFactory.getLogger(GraphqlProducer.class);
+
+    private static final Integer OK_RESPONSE_CODE = 200;
+    private static final String OK_STATUS_RANGE = "200-299";
 
     private HttpClient httpClient;
     private boolean closeHttpClient;
 
+    public GraphqlProducer(GraphqlEndpoint endpoint) {
+        super(endpoint);
+    }
+
     @Override
     protected void doStart() throws Exception {
         super.doStart();
@@ -74,13 +99,38 @@ public class GraphqlProducer extends DefaultAsyncProducer {
             HttpEntity requestEntity = new StringEntity(requestBody, 
ContentType.APPLICATION_JSON);
 
             HttpPost httpPost = new HttpPost(httpUri);
+            httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
             httpPost.setHeader(HttpHeaders.ACCEPT, "application/json");
             httpPost.setHeader(HttpHeaders.ACCEPT_ENCODING, "gzip");
             httpPost.setEntity(requestEntity);
+            populateRequestHeaders(exchange, httpPost);
 
-            String responseContent = httpClient.execute(httpPost, response -> 
EntityUtils.toString(response.getEntity()));
+            httpClient.execute(httpPost, httpResponse -> {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Finished executing http: {} method: {}", 
httpUri, HttpPost.METHOD_NAME);
+                }
+                int responseCode = httpResponse.getCode();
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Http responseCode: {}", responseCode);
+                }
+                if (!getEndpoint().isThrowExceptionOnFailure()) {
+                    // if we do not use failed exception then populate 
response for all response codes
+                    populateResponse(exchange, httpResponse, 
getEndpoint().getHeaderFilterStrategy(), responseCode);
+                } else {
+                    boolean ok = HttpHelper.isStatusCodeOk(responseCode, 
OK_STATUS_RANGE);
+                    if (ok) {
+                        // only populate response for OK response
+                        populateResponse(exchange, httpResponse, 
getEndpoint().getHeaderFilterStrategy(), responseCode);
+                    } else {
+                        // also store response code when throwing exception
+                        populateResponseCode(exchange.getMessage(), 
httpResponse, responseCode);
 
-            exchange.getMessage().setBody(responseContent);
+                        // operation failed so populate exception to throw
+                        
exchange.setException(populateHttpOperationFailedException(exchange, 
httpResponse, responseCode));
+                    }
+                }
+                return null;
+            });
 
         } catch (Exception e) {
             exchange.setException(e);
@@ -90,6 +140,144 @@ public class GraphqlProducer extends DefaultAsyncProducer {
         return true;
     }
 
+    private void populateRequestHeaders(Exchange exchange, HttpPost 
httpRequest) {
+        HeaderFilterStrategy strategy = 
getEndpoint().getHeaderFilterStrategy();
+        final TypeConverter tc = exchange.getContext().getTypeConverter();
+        for (Map.Entry<String, Object> entry : 
exchange.getMessage().getHeaders().entrySet()) {
+            String key = entry.getKey();
+            // we should not add known headers
+
+            // skip known headers from graphql
+            boolean skip = getEndpoint().getQueryHeader() != null && 
key.equalsIgnoreCase(getEndpoint().getQueryHeader())
+                    || getEndpoint().getVariablesHeader() != null && 
key.equalsIgnoreCase(getEndpoint().getVariablesHeader());
+            if (skip) {
+                continue;
+            }
+
+            Object headerValue = entry.getValue();
+            if (headerValue != null) {
+                if (headerValue instanceof String || headerValue instanceof 
Integer || headerValue instanceof Long
+                        || headerValue instanceof Boolean || headerValue 
instanceof Date) {
+                    // optimise for common types
+                    String value = headerValue.toString();
+                    if (!strategy.applyFilterToCamelHeaders(key, value, 
exchange)) {
+                        httpRequest.addHeader(key, value);
+                    }
+                    continue;
+                }
+
+                // use an iterator as there can be multiple values. (must not 
use a delimiter, and allow empty values)
+                final Iterator<?> it = 
ObjectHelper.createIterator(headerValue, null, true);
+
+                HttpUtil.applyHeader(strategy, exchange, it, tc, key,
+                        (multiValues, prev) -> applyHeader(httpRequest, key, 
multiValues, prev));
+            }
+        }
+    }
+
+    private static void applyHeader(HttpUriRequest httpRequest, String key, 
List<String> multiValues, String prev) {
+        // add the value(s) as a http request header
+        if (multiValues != null) {
+            // use the default toString of a ArrayList to create in the form 
[xxx, yyy]
+            // if multi valued, for a single value, then just output the value 
as is
+            String s = multiValues.size() > 1 ? multiValues.toString() : 
multiValues.get(0);
+            httpRequest.addHeader(key, s);
+        } else if (prev != null) {
+            httpRequest.addHeader(key, prev);
+        }
+    }
+
+    private static void populateResponseCode(Message message, 
ClassicHttpResponse httpResponse, int responseCode) {
+        // optimize for 200 response code as the boxing is outside the cached 
integers
+        if (responseCode == 200) {
+            message.setHeader(Exchange.HTTP_RESPONSE_CODE, OK_RESPONSE_CODE);
+        } else {
+            message.setHeader(Exchange.HTTP_RESPONSE_CODE, responseCode);
+        }
+        if (httpResponse.getReasonPhrase() != null) {
+            message.setHeader(Exchange.HTTP_RESPONSE_TEXT, 
httpResponse.getReasonPhrase());
+        }
+    }
+
+    protected Exception populateHttpOperationFailedException(
+            Exchange exchange, ClassicHttpResponse httpResponse, int 
responseCode)
+            throws IOException, ParseException {
+        Exception answer;
+
+        String statusText = httpResponse.getReasonPhrase() != null ? 
httpResponse.getReasonPhrase() : null;
+        Map<String, String> headers = 
extractResponseHeaders(httpResponse.getHeaders());
+
+        Object responseBody = EntityUtils.toString(httpResponse.getEntity());
+
+        // make a defensive copy of the response body in the exception so its 
detached from the cache
+        String copy = null;
+        if (responseBody != null) {
+            copy = 
exchange.getContext().getTypeConverter().convertTo(String.class, exchange, 
responseBody);
+        }
+
+        Header locationHeader = httpResponse.getFirstHeader("location");
+        String uri = getEndpoint().getHttpUri().toString();
+        if (locationHeader != null && responseCode >= 300 && responseCode < 
400) {
+            answer = new HttpOperationFailedException(
+                    uri, responseCode, statusText, locationHeader.getValue(), 
headers, copy);
+        } else {
+            answer = new HttpOperationFailedException(uri, responseCode, 
statusText, null, headers, copy);
+        }
+
+        return answer;
+    }
+
+    protected void populateResponse(
+            Exchange exchange, ClassicHttpResponse httpResponse,
+            HeaderFilterStrategy strategy, int responseCode)
+            throws IOException, ParseException {
+
+        Message answer = exchange.getMessage();
+        populateResponseCode(answer, httpResponse, responseCode);
+
+        // We just make the out message is not create when extractResponseBody 
throws exception
+        Object responseBody = EntityUtils.toString(httpResponse.getEntity());
+        answer.setBody(responseBody);
+
+        // optimize to walk headers with an iterator which does not create a 
new array as getAllHeaders does
+        boolean found = false;
+        Iterator<Header> it = httpResponse.headerIterator();
+        while (it.hasNext()) {
+            Header header = it.next();
+            String name = header.getName();
+            String value = header.getValue();
+            if (!found && name.equalsIgnoreCase("content-type")) {
+                name = Exchange.CONTENT_TYPE;
+                exchange.setProperty(ExchangePropertyKey.CHARSET_NAME, 
IOHelper.getCharsetNameFromContentType(value));
+                found = true;
+            }
+            // use http helper to extract parameter value as it may contain 
multiple values
+            Object extracted = HttpHelper.extractHttpParameterValue(value);
+            if (strategy != null && 
!strategy.applyFilterToExternalHeaders(name, extracted, exchange)) {
+                HttpHelper.appendHeader(answer.getHeaders(), name, extracted);
+            }
+        }
+    }
+
+    /**
+     * Extracts the response headers
+     *
+     * @param  responseHeaders the headers
+     * @return                 the extracted headers or an empty map if no 
headers existed
+     */
+    protected static Map<String, String> extractResponseHeaders(Header[] 
responseHeaders) {
+        if (responseHeaders == null || responseHeaders.length == 0) {
+            return Map.of();
+        }
+
+        Map<String, String> answer = new HashMap<>();
+        for (Header header : responseHeaders) {
+            answer.put(header.getName(), header.getValue());
+        }
+
+        return answer;
+    }
+
     protected static String buildRequestBody(String query, String 
operationName, JsonObject variables) {
         JsonObject jsonObject = new JsonObject();
         jsonObject.put("query", query);
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 24cff92c41ae..96459894721d 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
@@ -25,6 +25,7 @@ import org.apache.camel.EndpointInject;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.graphql.server.GraphqlServer;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.http.base.HttpOperationFailedException;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.apache.camel.util.IOHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -34,6 +35,8 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.fail;
 
 public class GraphqlComponentTest extends CamelTestSupport {
 
@@ -118,6 +121,10 @@ public class GraphqlComponentTest extends CamelTestSupport 
{
                 from("direct:start8")
                         .to("graphql://http://localhost:"; + server.getPort() + 
"/graphql?apikey=123456&query={books{id name}}")
                         .to("mock:result");
+                from("direct:start9")
+                        .setHeader("foo", constant("cheese"))
+                        .to("graphql://http://localhost:"; + server.getPort() + 
"/graphql?query={books{id name}}")
+                        .to("mock:result");
             }
         };
     }
@@ -208,7 +215,6 @@ public class GraphqlComponentTest extends CamelTestSupport {
 
     @Test
     public void checkApiKey() throws Exception {
-
         GraphqlEndpoint graphqlEndpoint = (GraphqlEndpoint) 
template.getCamelContext().getEndpoint(
                 "graphql://http://localhost:"; + server.getPort() + 
"/graphql?apikey=123456&query={books{id name}}");
         URI httpUri = graphqlEndpoint.getHttpUri();
@@ -220,6 +226,34 @@ public class GraphqlComponentTest extends CamelTestSupport 
{
         template.sendBody("direct:start8", "");
 
         result.assertIsSatisfied();
+    }
+
+    @Test
+    public void checkCustomHeader() throws Exception {
+        result.expectedMessageCount(1);
+        result.expectedBodiesReceived(booksQueryResult);
+        result.expectedHeaderReceived("foo", "cheese");
+        result.expectedHeaderReceived("bar", "response-cheese");
+
+        template.sendBody("direct:start9", "");
+
+        result.assertIsSatisfied();
+    }
 
+    @Test
+    public void checkThrowException() throws Exception {
+        result.expectedMessageCount(0);
+
+        try {
+            template.sendBodyAndHeader("direct:start9", "", "kaboom", "force 
some error");
+            fail();
+        } catch (Exception e) {
+            HttpOperationFailedException he = 
assertInstanceOf(HttpOperationFailedException.class, e.getCause());
+            assertEquals(500, he.getStatusCode());
+            assertEquals("Forced error due to kaboom", 
he.getHttpResponseStatus());
+        }
+
+        result.assertIsSatisfied();
     }
+
 }
diff --git 
a/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/server/GraphqlServer.java
 
b/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/server/GraphqlServer.java
index 43edb1942bdc..65f71c622482 100644
--- 
a/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/server/GraphqlServer.java
+++ 
b/components/camel-graphql/src/test/java/org/apache/camel/component/graphql/server/GraphqlServer.java
@@ -26,6 +26,7 @@ import graphql.ExecutionResult;
 import graphql.GraphQL;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
+import org.apache.hc.core5.http.Header;
 import org.apache.hc.core5.http.HttpEntity;
 import org.apache.hc.core5.http.HttpException;
 import org.apache.hc.core5.http.impl.bootstrap.HttpServer;
@@ -68,8 +69,15 @@ public class GraphqlServer {
         public void handle(ClassicHttpRequest request, ClassicHttpResponse 
response, HttpContext context)
                 throws HttpException, IOException {
             HttpEntity entity = request.getEntity();
-            String json = EntityUtils.toString(entity);
 
+            Header h = request.getHeader("kaboom");
+            if (h != null) {
+                response.setCode(500);
+                response.setReasonPhrase("Forced error due to kaboom");
+                return;
+            }
+
+            String json = EntityUtils.toString(entity);
             Map<String, Object> map = jsonToMap(json);
             String query = (String) map.get("query");
             String operationName = (String) map.get("operationName");
@@ -84,6 +92,10 @@ public class GraphqlServer {
             Map<String, Object> resultMap = executionResult.toSpecification();
             String result = objectMapper.writeValueAsString(resultMap);
 
+            h = request.getHeader("foo");
+            if (h != null) {
+                response.setHeader("bar", "response-" + h.getValue());
+            }
             response.setHeader("Content-Type", "application/json; 
charset=UTF-8");
             response.setEntity(new StringEntity(result));
         }
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_16.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_16.adoc
index 2a081cefa188..624cb5f2e95f 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_16.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_16.adoc
@@ -18,6 +18,13 @@ See the xref:camel-upgrade-recipes-tool.adoc[documentation] 
page for details.
 The kamelet component is now parsing endpoint parameters using _raw mode_ to 
ensure when using sensitive parameters
 such as access keys, passwords etc. they are not URI encoded.
 
+=== camel-graphql
+
+The `camel-graphql` component now includes Camel message headers as HTTP 
headers when calling the remote Graphql server.
+
+If the response is not success (2xx) then the component now throws the 
`org.apache.camel.http.base.HttpOperationFailedException`.
+This can be turned off by setting `throwExceptionOnFailure=false`.
+
 === camel-infinispan
 
 The `queryBuilder` option on `camel-infinispan` endpoint has been migrated to 
no longer use the deprecated query factory
diff --git 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GraphqlComponentBuilderFactory.java
 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GraphqlComponentBuilderFactory.java
index 6d52e8c94392..7c89c77f6bf9 100644
--- 
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GraphqlComponentBuilderFactory.java
+++ 
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/GraphqlComponentBuilderFactory.java
@@ -76,6 +76,25 @@ public interface GraphqlComponentBuilderFactory {
         }
     
         
+        /**
+         * Option to disable throwing the HttpOperationFailedException in case
+         * of failed responses from the remote server. This allows you to get
+         * all responses regardless of the HTTP status code.
+         * 
+         * The option is a: &lt;code&gt;boolean&lt;/code&gt; type.
+         * 
+         * Default: true
+         * Group: producer
+         * 
+         * @param throwExceptionOnFailure the value to set
+         * @return the dsl builder
+         */
+        default GraphqlComponentBuilder throwExceptionOnFailure(boolean 
throwExceptionOnFailure) {
+            doSetProperty("throwExceptionOnFailure", throwExceptionOnFailure);
+            return this;
+        }
+    
+        
         /**
          * Whether autowiring is enabled. This is used for automatic autowiring
          * options (the option must be marked as autowired) by looking up in 
the
@@ -114,6 +133,24 @@ public interface GraphqlComponentBuilderFactory {
             doSetProperty("httpClient", httpClient);
             return this;
         }
+    
+        /**
+         * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter
+         * header to and from Camel message.
+         * 
+         * The option is a:
+         * &lt;code&gt;org.apache.camel.spi.HeaderFilterStrategy&lt;/code&gt;
+         * type.
+         * 
+         * Group: filter
+         * 
+         * @param headerFilterStrategy the value to set
+         * @return the dsl builder
+         */
+        default GraphqlComponentBuilder 
headerFilterStrategy(org.apache.camel.spi.HeaderFilterStrategy 
headerFilterStrategy) {
+            doSetProperty("headerFilterStrategy", headerFilterStrategy);
+            return this;
+        }
     }
 
     class GraphqlComponentBuilderImpl
@@ -130,8 +167,10 @@ public interface GraphqlComponentBuilderFactory {
                 Object value) {
             switch (name) {
             case "lazyStartProducer": ((GraphqlComponent) 
component).setLazyStartProducer((boolean) value); return true;
+            case "throwExceptionOnFailure": ((GraphqlComponent) 
component).setThrowExceptionOnFailure((boolean) value); return true;
             case "autowiredEnabled": ((GraphqlComponent) 
component).setAutowiredEnabled((boolean) value); return true;
             case "httpClient": ((GraphqlComponent) 
component).setHttpClient((org.apache.hc.client5.http.classic.HttpClient) 
value); return true;
+            case "headerFilterStrategy": ((GraphqlComponent) 
component).setHeaderFilterStrategy((org.apache.camel.spi.HeaderFilterStrategy) 
value); return true;
             default: return false;
             }
         }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
index 85147f4ee54f..055e6853409b 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/GraphqlEndpointBuilderFactory.java
@@ -115,6 +115,40 @@ public interface GraphqlEndpointBuilderFactory {
             doSetProperty("queryHeader", queryHeader);
             return this;
         }
+        /**
+         * Option to disable throwing the HttpOperationFailedException in case
+         * of failed responses from the remote server. This allows you to get
+         * all responses regardless of the HTTP status code.
+         * 
+         * The option is a: <code>boolean</code> type.
+         * 
+         * Default: true
+         * Group: producer
+         * 
+         * @param throwExceptionOnFailure the value to set
+         * @return the dsl builder
+         */
+        default GraphqlEndpointBuilder throwExceptionOnFailure(boolean 
throwExceptionOnFailure) {
+            doSetProperty("throwExceptionOnFailure", throwExceptionOnFailure);
+            return this;
+        }
+        /**
+         * Option to disable throwing the HttpOperationFailedException in case
+         * of failed responses from the remote server. This allows you to get
+         * all responses regardless of the HTTP status code.
+         * 
+         * The option will be converted to a <code>boolean</code> type.
+         * 
+         * Default: true
+         * Group: producer
+         * 
+         * @param throwExceptionOnFailure the value to set
+         * @return the dsl builder
+         */
+        default GraphqlEndpointBuilder throwExceptionOnFailure(String 
throwExceptionOnFailure) {
+            doSetProperty("throwExceptionOnFailure", throwExceptionOnFailure);
+            return this;
+        }
         /**
          * The JsonObject instance containing the operation variables.
          * 
@@ -229,6 +263,38 @@ public interface GraphqlEndpointBuilderFactory {
             return (GraphqlEndpointBuilder) this;
         }
 
+        /**
+         * To use a custom HeaderFilterStrategy to filter header to and from
+         * Camel message.
+         * 
+         * The option is a:
+         * <code>org.apache.camel.spi.HeaderFilterStrategy</code> type.
+         * 
+         * Group: common (advanced)
+         * 
+         * @param headerFilterStrategy the value to set
+         * @return the dsl builder
+         */
+        default AdvancedGraphqlEndpointBuilder 
headerFilterStrategy(org.apache.camel.spi.HeaderFilterStrategy 
headerFilterStrategy) {
+            doSetProperty("headerFilterStrategy", headerFilterStrategy);
+            return this;
+        }
+        /**
+         * To use a custom HeaderFilterStrategy to filter header to and from
+         * Camel message.
+         * 
+         * The option will be converted to a
+         * <code>org.apache.camel.spi.HeaderFilterStrategy</code> type.
+         * 
+         * Group: common (advanced)
+         * 
+         * @param headerFilterStrategy the value to set
+         * @return the dsl builder
+         */
+        default AdvancedGraphqlEndpointBuilder headerFilterStrategy(String 
headerFilterStrategy) {
+            doSetProperty("headerFilterStrategy", headerFilterStrategy);
+            return this;
+        }
         /**
          * Whether the producer should be started lazy (on the first message).
          * By starting lazy you can use this to allow CamelContext and routes 
to

Reply via email to