= CXF-RS Component
:doctitle: CXF-RS
:shortname: cxfrs
:artifactid: camel-cxf-rest
:description: Expose JAX-RS REST services using Apache CXF or connect to external REST services using CXF REST client.
:since: 2.0
:supportlevel: Stable
:tabs-sync-option:
:component-header: Both producer and consumer are supported
//Manually maintained attributes
:camel-spring-boot-name: cxf-rest

*Since Camel {since}*

*{component-header}*

The CXFRS component provides integration with http://cxf.apache.org[Apache CXF] for connecting to JAX-RS 1.1 and 2.0 services hosted in CXF.

Maven users will need to add the following dependency to their pom.xml
for this component:

[source,xml]
-------------------------------------------------------------------------------------
<dependency>
   <groupId>org.apache.camel</groupId>
   <artifactId>camel-cxf-rest</artifactId>
   <version>x.x.x</version>  <!-- use the same version as your Camel core version -->
</dependency>
-------------------------------------------------------------------------------------

== URI format

-----------------------
cxfrs://address?options
-----------------------

Where *address* represents the CXF endpoint's address

---------------------
cxfrs:bean:rsEndpoint
---------------------

Where *rsEndpoint* represents the spring bean's name, which presents the
CXFRS client or server

For either style above, you can append options to the URI as follows:

------------------------------------------------------------------
cxfrs:bean:cxfEndpoint?resourceClasses=org.apache.camel.rs.Example
------------------------------------------------------------------


// component-configure options: START

// component-configure options: END

// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
// component options: END

// endpoint options: START

// endpoint options: END

// component headers: START
include::partial$component-endpoint-headers.adoc[]
// component headers: END

You can also configure the CXF REST endpoint through the spring
configuration.


[NOTE]
====
Since there are lots of differences between the CXF REST
client and CXF REST Server, we provide different configuration for
them.

Please check the following files for more details:

* the https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-spring-rest/src/main/resources/schema/cxfJaxrsEndpoint.xsd[schema file].
* http://cxf.apache.org/docs/jax-rs.html[CXF JAX-RS documentation].
====

== Examples

=== How to configure the REST endpoint in Camel

In the
https://github.com/apache/camel/blob/main/components/camel-cxf/camel-cxf-spring-rest/src/main/resources/schema/cxfJaxrsEndpoint.xsd[camel-cxf schema file], there are two elements for the REST endpoint definition:

* `cxf:rsServer` for REST consumer
* `cxf:rsClient` for REST producer.

You can find a Camel REST service route configuration example there.

=== How to override the CXF producer address from message header

The `camel-cxfrs` producer supports overriding the service address by setting the message with the key of `CamelDestinationOverrideUrl`.

[source,java]
----------------------------------------------------------------------------------------------
 // set up the service address from the message header to override the setting of CXF endpoint
 exchange.getIn().setHeader(Exchange.DESTINATION_OVERRIDE_URL, constant(getServiceAddress()));
----------------------------------------------------------------------------------------------

=== Consuming a REST Request - Simple Binding Style

*Since Camel 2.11*

The `Default` binding style is rather low-level, requiring the user to
manually process the `MessageContentsList` object coming into the route.
Thus, it tightly couples the route logic with the method signature and
parameter indices of the JAX-RS operation. Somewhat inelegant, difficult
and error-prone.

In contrast, the `SimpleConsumer` binding style performs the following
mappings, to *make the request data more accessible* to you
within the Camel Message:

* JAX-RS Parameters (`@HeaderParam`, `@QueryParam`, etc.) are injected as _IN_
message headers. The header name matches the value of the annotation.
* The request entity (POJO or another type) becomes the _IN_ message body.
If a single entity cannot be identified in the JAX-RS method signature,
it falls back to the original `MessageContentsList`.
* Binary `@Multipart` body parts become _IN_ message attachments,
supporting `DataHandler`, `InputStream`, `DataSource` and CXF's
`Attachment` class.
* Non-binary `@Multipart` body parts are mapped as _IN_ message headers.
The header name matches the Body Part name.

Additionally, the following rules apply to the *Response mapping*:

* If the message body type is different to `javax.ws.rs.core.Response`
(user-built response), a new `Response` is created and the message body
is set as the entity (so long it's not null). The response status code
is taken from the `Exchange.HTTP_RESPONSE_CODE` header, or defaults to
200 OK if not present.
* If the message body type is equal to `javax.ws.rs.core.Response`, it
means that the user has built a custom response, and therefore it is
respected, and it becomes the final response.
* In all cases, Camel headers permitted by custom or default
`HeaderFilterStrategy` are added to the HTTP response.

=== Enabling the Simple Binding Style

This binding style can be activated by setting the `bindingStyle`
parameter in the consumer endpoint to value `SimpleConsumer`:

[source,java]
---------------------------------------------------------
  from("cxfrs:bean:rsServer?bindingStyle=SimpleConsumer")
    .to("log:TEST?showAll=true");
---------------------------------------------------------

=== Examples of request binding with different method signatures

Below is a list of method signatures along with the expected result from the simple binding:

* `public Response doAction(BusinessObject request);`: the request payload is placed in tbe _IN_ message body, replacing the original MessageContentsList.

* `public Response doAction(BusinessObject request, @HeaderParam("abcd") String abcd, @QueryParam("defg") String defg);`: the request payload is placed in the _IN_ message body, replacing the original `MessageContentsList`. Both request parameters are mapped as IN message headers
with names _"abcd"_ and _"defg"_.

* `public Response doAction(@HeaderParam("abcd") String abcd, @QueryParam("defg") String defg);`: both request parameters are mapped as the _IN_ message headers with names _"abcd"_ and
_"defg"_. The original `MessageContentsList` is preserved, even though it only contains the two parameters.

* `public Response doAction(@Multipart(value="body1") BusinessObject request, @Multipart(value="body2") BusinessObject request2);`: the first parameter is transferred as a header with name _"body1"_, and the second one is mapped as header _"body2"_. The original `MessageContentsList`
is preserved as the _IN_ message body.

* `public Response doAction(InputStream abcd);`: the `InputStream` is unwrapped from the `MessageContentsList` and preserved as the _IN_ message body.

* `public Response doAction(DataHandler abcd);`: the _DataHandler_ is unwrapped from the `MessageContentsList` and preserved as the _IN_ message body.

=== More examples of the Simple Binding Style

Given a JAX-RS resource class with this method:

[source,java]
------------------------------------------------------------------------------------------------------------------------------------------------
@POST @Path("/customers/{type}")
public Response newCustomer(Customer customer, @PathParam("type") String type, @QueryParam("active") @DefaultValue("true") boolean active) {
    return null;
}
------------------------------------------------------------------------------------------------------------------------------------------------

Serviced by the following route:

[source,java]
--------------------------------------------------------------------------------------------
from("cxfrs:bean:rsServer?bindingStyle=SimpleConsumer")
    .recipientList(simple("direct:${header.operationName}"));

from("direct:newCustomer")
    .log("Request: type=${header.type}, active=${header.active}, customerData=${body}");
--------------------------------------------------------------------------------------------

The following HTTP request with XML payload (given that the Customer DTO is JAXB-annotated):

-------------------------------------
POST /customers/gold?active=true

Payload:
<Customer>
  <fullName>Raul Kripalani</fullName>
  <country>Spain</country>
  <project>Apache Camel</project>
</Customer>
-------------------------------------

Will print the message:

----------------------------------------------------------------------------------
Request: type=gold, active=true, customerData=<Customer.toString() representation>
----------------------------------------------------------------------------------

[NOTE]
====
More examples on how to process requests and write responses can be
found
https://github.com/apache/camel/tree/main/components/camel-cxf/camel-cxf-rest/src/test/java/org/apache/camel/component/cxf/jaxrs/simplebinding[here].
====

=== Consuming a REST Request - Default Binding Style

The http://cxf.apache.org/docs/jax-rs.html[CXF JAXRS front end]
implements the https://javaee.github.io/jsr311/[JAX-RS (JSR-311) API], so we can
export the resource classes as a REST service. And we leverage the
http://cxf.apache.org/docs/invokers.html[CXF Invoker
API] to turn a REST request into a normal Java object method
invocation.
You don't need to specify the URI template within your endpoint, CXF takes care
of the REST request URI to resource class method mapping according to the
JSR-311 specification. All you need to do in Camel is delegate this
method request to the right processor or endpoint.

Here is an example of a CXFRS route...
[source,java]
----
private static final String CXF_RS_ENDPOINT_URI =
        "cxfrs://http://localhost:" + CXT + "/rest?resourceClasses=org.apache.camel.component.cxf.jaxrs.testbean.CustomerServiceResource";
private static final String CXF_RS_ENDPOINT_URI2 =
        "cxfrs://http://localhost:" + CXT + "/rest2?resourceClasses=org.apache.camel.component.cxf.jaxrs.testbean.CustomerService";
private static final String CXF_RS_ENDPOINT_URI3 =
        "cxfrs://http://localhost:" + CXT + "/rest3?"
        + "resourceClasses=org.apache.camel.component.cxf.jaxrs.testbean.CustomerServiceNoAnnotations&"
        + "modelRef=classpath:/org/apache/camel/component/cxf/jaxrs/CustomerServiceModel.xml";
private static final String CXF_RS_ENDPOINT_URI4 =
        "cxfrs://http://localhost:" + CXT + "/rest4?"
        + "modelRef=classpath:/org/apache/camel/component/cxf/jaxrs/CustomerServiceDefaultHandlerModel.xml";
private static final String CXF_RS_ENDPOINT_URI5 =
        "cxfrs://http://localhost:" + CXT + "/rest5?"
        + "propagateContexts=true&"
        + "modelRef=classpath:/org/apache/camel/component/cxf/jaxrs/CustomerServiceDefaultHandlerModel.xml";
protected RouteBuilder createRouteBuilder() throws Exception {
    final Processor testProcessor = new TestProcessor();
    final Processor testProcessor2 = new TestProcessor2();
    final Processor testProcessor3 = new TestProcessor3();
    return new RouteBuilder() {
        public void configure() {
            errorHandler(new NoErrorHandlerBuilder());
            from(CXF_RS_ENDPOINT_URI).process(testProcessor);
            from(CXF_RS_ENDPOINT_URI2).process(testProcessor);
            from(CXF_RS_ENDPOINT_URI3).process(testProcessor);
            from(CXF_RS_ENDPOINT_URI4).process(testProcessor2);
            from(CXF_RS_ENDPOINT_URI5).process(testProcessor3);
        }
    };
}
----

And the corresponding resource class used to configure the endpoint...

[NOTE]
====
*Note about resource classes*

By default, JAX-RS resource classes are *only* used to configure JAX-RS
properties. Methods will *not* be executed during routing of messages to
the endpoint. Instead, it is the responsibility of the route to do all
processing.
====

It is sufficient to provide an
interface only as opposed to a no-op service implementation class for
the default mode.

If a *performInvocation* option is enabled,
the service implementation will be invoked first, the response will be
set on the Camel exchange, and the route execution will continue as
usual. This can be useful for integrating the existing JAX-RS implementations into Camel routes and
for post-processing JAX-RS Responses in custom processors.

[source,java]
----
@Path("/customerservice/")
public interface CustomerServiceResource {

    @GET
    @Path("/customers/{id}/")
    Customer getCustomer(@PathParam("id") String id);

    @PUT
    @Path("/customers/")
    Response updateCustomer(Customer customer);

    @Path("/{id}")
    @PUT()
    @Consumes({ "application/xml", "text/plain",
                    "application/json" })
    @Produces({ "application/xml", "text/plain",
                    "application/json" })
    Object invoke(@PathParam("id") String id,
                    String payload);
}
----

=== How to invoke the REST service through camel-cxfrs producer

The http://cxf.apache.org/docs/jax-rs.html[CXF JAXRS front end]
implements
http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-Proxy-basedAPI[a
proxy-based client API], with this API you can invoke the remote REST
service through a proxy. The `camel-cxfrs` producer is based on this
http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-Proxy-basedAPI[proxy
API].
 You need to specify the operation name in the message header and
prepare the parameter in the message body, the camel-cxfrs producer will
 generate the right REST request for you.

Here is an example:
[source,java]
----
Exchange exchange = template.send("direct://proxy", new Processor() {
    public void process(Exchange exchange) throws Exception {
        exchange.setPattern(ExchangePattern.InOut);
        Message inMessage = exchange.getIn();
        // set the operation name
        inMessage.setHeader(CxfConstants.OPERATION_NAME, "getCustomer");
        // using the proxy client API
        inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.FALSE);
        // set a customer header
        inMessage.setHeader("key", "value");
        // set up the accepted content type
        inMessage.setHeader(Exchange.ACCEPT_CONTENT_TYPE, "application/json");
        // set the parameters, if you just have one parameter,
        // camel will put this object into an Object[] itself
        inMessage.setBody("123");
    }
});

// get the response message
Customer response = (Customer) exchange.getMessage().getBody();

assertNotNull(response, "The response should not be null");
assertEquals(123, response.getId(), "Get a wrong customer id");
assertEquals("John", response.getName(), "Get a wrong customer name");
assertEquals(200, exchange.getMessage().getHeader(Exchange.HTTP_RESPONSE_CODE), "Get a wrong response code");
assertEquals("value", exchange.getMessage().getHeader("key"), "Get a wrong header value");
----

The http://cxf.apache.org/docs/jax-rs.html[CXF JAXRS front end] also
provides
http://cxf.apache.org/docs/jax-rs-client-api.html#JAX-RSClientAPI-CXFWebClientAPI[an HTTP centric client API]. You can also invoke this API from
`camel-cxfrs` producer. You need to specify the
https://www.javadoc.io/doc/org.apache.camel/camel-api/current/org/apache/camel/Exchange.html#HTTP_PATH[HTTP_PATH]
and
the https://www.javadoc.io/doc/org.apache.camel/camel-api/current/org/apache/camel/Exchange.html#HTTP_METHOD[HTTP_METHOD] and
let the producer use the http centric client API by using the URI option
*httpClientAPI* or by setting the message header
https://www.javadoc.io/doc/org.apache.camel/camel-cxf-transport/current/org/apache/camel/component/cxf/common/message/CxfConstants.html#CAMEL_CXF_RS_USING_HTTP_API[CxfConstants.CAMEL_CXF_RS_USING_HTTP_API].
You can turn the response object to the type class specified with the
message
header https://www.javadoc.io/doc/org.apache.camel/camel-cxf-transport/current/org/apache/camel/component/cxf/common/message/CxfConstants.html#CAMEL_CXF_RS_RESPONSE_CLASS[CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS].
[source,java]
----
Exchange exchange = template.send("direct://http", new Processor() {
    public void process(Exchange exchange) throws Exception {
        exchange.setPattern(ExchangePattern.InOut)
        Message inMessage = exchange.getIn();
        // using the http central client API
        inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, Boolean.TRUE);
        // set the Http method
        inMessage.setHeader(Exchange.HTTP_METHOD, "GET");
        // set the relative path
        inMessage.setHeader(Exchange.HTTP_PATH, "/customerservice/customers/123");
        // Specify the response class, cxfrs will use InputStream as the response object type
        inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_RESPONSE_CLASS, Customer.class);
        // set a customer header
        inMessage.setHeader("key", "value");
        // since we use the Get method, so we don't need to set the message body
        inMessage.setBody(null);
    }
});
----
We also support to specify the query parameters from
cxfrs URI for the CXFRS http centric client.
[source,java]
----
Exchange exchange = template.send("cxfrs://http://localhost:9003/testQuery?httpClientAPI=true&q1=12&q2=13"
----
To support the Dynamical routing, you can override the URI's query
parameters by using the https://www.javadoc.io/doc/org.apache.camel/camel-cxf-transport/current/org/apache/camel/component/cxf/common/message/CxfConstants.html#CAMEL_CXF_RS_QUERY_MAP[CxfConstants.CAMEL_CXF_RS_QUERY_MAP]
header to set the parameter map for it.
[source,java]
----
Map<String, String> queryMap = new LinkedHashMap<>();
queryMap.put("q1", "new");
queryMap.put("q2", "world");
inMessage.setHeader(CxfConstants.CAMEL_CXF_RS_QUERY_MAP, queryMap);
----


include::spring-boot:partial$starter.adoc[]
