You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2022/03/18 10:05:37 UTC

[camel-quarkus] 02/12: Increase FHIR extension test coverage

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

jamesnetherton pushed a commit to branch 2.7.x
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit d6bf08b9c95335cce2f3f381773a61ddf4ab178a
Author: James Netherton <ja...@gmail.com>
AuthorDate: Fri Mar 11 15:41:08 2022 +0000

    Increase FHIR extension test coverage
    
    Fixes #3601
---
 .../component/fhir/deployment/FhirProcessor.java   |   15 +-
 .../fhir/it/AbstractFhirRouteBuilder.java          |  248 +++++
 .../quarkus/component/fhir/it/FhirConstants.java}  |   10 +-
 .../component/fhir/it/FhirDstu2Resource.java       | 1177 +++++++++++++++++++-
 .../component/fhir/it/FhirDstu2RouteBuilder.java   |   38 +-
 .../component/fhir/it/FhirDstu3Resource.java       | 1170 ++++++++++++++++++-
 .../component/fhir/it/FhirDstu3RouteBuilder.java   |   38 +-
 .../quarkus/component/fhir/it/FhirR4Resource.java  | 1163 ++++++++++++++++++-
 .../component/fhir/it/FhirR4RouteBuilder.java      |   38 +-
 .../quarkus/component/fhir/it/FhirR5Resource.java  | 1161 ++++++++++++++++++-
 .../component/fhir/it/FhirR5RouteBuilder.java      |   38 +-
 .../fhir/src/main/resources/application.properties |   15 +-
 .../component/fhir/it/AbstractFhirTest.java        |  883 +++++++++++++++
 .../quarkus/component/fhir/it/FhirClientTest.java  |  113 --
 .../component/fhir/it/FhirDataformatTest.java      |  164 ---
 .../it/{FhirClientIT.java => FhirDstu2IT.java}     |    5 +-
 .../quarkus/component/fhir/it/FhirDstu2Test.java   |   50 +
 .../it/{FhirClientIT.java => FhirDstu3IT.java}     |    5 +-
 .../quarkus/component/fhir/it/FhirDstu3Test.java   |   49 +
 .../fhir/it/{FhirClientIT.java => FhirR4IT.java}   |    5 +-
 .../fhir/it/{FhirClientIT.java => FhirR4Test.java} |   14 +-
 .../it/{FhirDataformatIT.java => FhirR5IT.java}    |    6 +-
 .../it/{FhirDataformatIT.java => FhirR5Test.java}  |   14 +-
 .../component/fhir/it/FhirTestResource.java        |   78 +-
 .../{FhirClientIT.java => util/Dstu2Enabled.java}  |   12 +-
 .../{FhirClientIT.java => util/Dstu3Enabled.java}  |   12 +-
 .../component/fhir/it/util/FhirTestHelper.java     |   42 +
 .../it/{FhirClientIT.java => util/R4Enabled.java}  |   12 +-
 .../it/{FhirClientIT.java => util/R5Enabled.java}  |   12 +-
 29 files changed, 6064 insertions(+), 523 deletions(-)

diff --git a/extensions/fhir/deployment/src/main/java/org/apache/camel/quarkus/component/fhir/deployment/FhirProcessor.java b/extensions/fhir/deployment/src/main/java/org/apache/camel/quarkus/component/fhir/deployment/FhirProcessor.java
index 64568e8..9dd642e 100644
--- a/extensions/fhir/deployment/src/main/java/org/apache/camel/quarkus/component/fhir/deployment/FhirProcessor.java
+++ b/extensions/fhir/deployment/src/main/java/org/apache/camel/quarkus/component/fhir/deployment/FhirProcessor.java
@@ -17,15 +17,19 @@
 package org.apache.camel.quarkus.component.fhir.deployment;
 
 import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
+import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
 import ca.uhn.fhir.util.jar.DependencyLogImpl;
 import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
 import io.quarkus.deployment.annotations.BuildProducer;
 import io.quarkus.deployment.annotations.BuildStep;
 import io.quarkus.deployment.builditem.AdditionalApplicationArchiveMarkerBuildItem;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
 import io.quarkus.deployment.builditem.ExtensionSslNativeSupportBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
 
 final class FhirProcessor {
     private static final String FEATURE = "camel-fhir";
@@ -56,7 +60,16 @@ final class FhirProcessor {
     }
 
     @BuildStep()
-    void processFhir(BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+    void registerForReflection(
+            CombinedIndexBuildItem combinedIndex,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
+
+        IndexView index = combinedIndex.getIndex();
+        index.getAllKnownSubclasses(DotName.createSimple(BaseServerResponseException.class.getName()))
+                .stream()
+                .map(classInfo -> new ReflectiveClassBuildItem(false, false, classInfo.name().toString()))
+                .forEach(reflectiveClass::produce);
+
         reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, true, SchematronBaseValidator.class));
         reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, true, DependencyLogImpl.class));
         reflectiveClass.produce(new ReflectiveClassBuildItem(true, true, true, ApacheRestfulClientFactory.class));
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirRouteBuilder.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirRouteBuilder.java
new file mode 100644
index 0000000..0ec505e
--- /dev/null
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirRouteBuilder.java
@@ -0,0 +1,248 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.fhir.it;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.parser.StrictErrorHandler;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.fhir.FhirComponent;
+import org.apache.camel.component.fhir.FhirConfiguration;
+import org.apache.camel.component.fhir.FhirJsonDataFormat;
+import org.apache.camel.component.fhir.FhirXmlDataFormat;
+import org.eclipse.microprofile.config.Config;
+import org.eclipse.microprofile.config.ConfigProvider;
+
+public abstract class AbstractFhirRouteBuilder extends RouteBuilder {
+
+    abstract String getFhirVersion();
+
+    abstract FhirContext getFhirContext();
+
+    abstract boolean isEnabled();
+
+    @Override
+    public void configure() throws Exception {
+        if (isEnabled()) {
+            Config config = ConfigProvider.getConfig();
+            String fhirVersion = getFhirVersion();
+            String serverUrl = config.getValue("camel.fhir." + fhirVersion + ".test-url", String.class);
+
+            FhirContext fhirContext = getFhirContext();
+
+            FhirConfiguration configuration = new FhirConfiguration();
+            configuration.setLog(false);
+            configuration.setFhirContext(fhirContext);
+            configuration.setServerUrl(serverUrl);
+            configuration.setCompress(true);
+
+            FhirComponent component = new FhirComponent();
+            component.setConfiguration(configuration);
+            getContext().addComponent("fhir-" + fhirVersion, component);
+
+            fhirContext.setParserErrorHandler(new StrictErrorHandler());
+            try {
+                URL url = new URL(serverUrl);
+                fhirContext.getRestfulClientFactory().setProxy(url.getHost(), url.getPort());
+            } catch (MalformedURLException e) {
+                throw new RuntimeException(e);
+            }
+
+            FhirJsonDataFormat fhirJsonDataFormat = new FhirJsonDataFormat();
+            fhirJsonDataFormat.setFhirContext(fhirContext);
+            fhirJsonDataFormat.setParserErrorHandler(new StrictErrorHandler());
+
+            FhirXmlDataFormat fhirXmlDataFormat = new FhirXmlDataFormat();
+            fhirXmlDataFormat.setFhirContext(fhirContext);
+            fhirXmlDataFormat.setParserErrorHandler(new StrictErrorHandler());
+
+            // Capabilities
+            fromF("direct:capabilities-%s", fhirVersion)
+                    .toF("fhir-%s://capabilities/ofType?inBody=type", fhirVersion);
+
+            // Create
+            fromF("direct:createResource-%s", fhirVersion)
+                    .toF("fhir-%s://create/resource?inBody=resource", fhirVersion);
+
+            fromF("direct:createResourceAsString-%s", fhirVersion)
+                    .toF("fhir-%s://create/resource?inBody=resourceAsString", fhirVersion);
+
+            // Dataformats
+            fromF("direct:json-to-%s", fhirVersion)
+                    .unmarshal(fhirJsonDataFormat)
+                    .marshal(fhirJsonDataFormat);
+
+            fromF("direct:xml-to-%s", fhirVersion)
+                    .unmarshal(fhirXmlDataFormat)
+                    .marshal(fhirXmlDataFormat);
+
+            // Delete
+            fromF("direct:delete-%s", fhirVersion)
+                    .toF("fhir-%s://delete/resource?inBody=resource", fhirVersion);
+
+            fromF("direct:deleteById-%s", fhirVersion)
+                    .toF("fhir-%s://delete/resourceById?inBody=id", fhirVersion);
+
+            fromF("direct:deleteByStringId-%s", fhirVersion)
+                    .toF("fhir-%s://delete/resourceById", fhirVersion);
+
+            fromF("direct:deleteConditionalByUrl-%s", fhirVersion)
+                    .toF("fhir-%s://delete/resourceConditionalByUrl?inBody=url", fhirVersion);
+
+            // History
+            fromF("direct:historyOnInstance-%s", fhirVersion)
+                    .toF("fhir-%s://history/onInstance", fhirVersion);
+
+            fromF("direct:historyOnServer-%s", fhirVersion)
+                    .toF("fhir-%s://history/onServer", fhirVersion);
+
+            fromF("direct:historyOnType-%s", fhirVersion)
+                    .toF("fhir-%s://history/onType", fhirVersion);
+
+            // Load page
+            fromF("direct:loadPageByUrl-%s", fhirVersion)
+                    .toF("fhir-%s://load-page/byUrl", fhirVersion);
+
+            fromF("direct:loadPageNext-%s", fhirVersion)
+                    .toF("fhir-%s://load-page/next?inBody=bundle", fhirVersion);
+
+            fromF("direct:loadPagePrevious-%s", fhirVersion)
+                    .toF("fhir-%s://load-page/previous?inBody=bundle", fhirVersion);
+
+            // Meta
+            fromF("direct:metaAdd-%s", fhirVersion)
+                    .toF("fhir-%s://meta/add", fhirVersion);
+
+            fromF("direct:metaDelete-%s", fhirVersion)
+                    .toF("fhir-%s://meta/delete", fhirVersion);
+
+            fromF("direct:metaGetFromResource-%s", fhirVersion)
+                    .toF("fhir-%s://meta/getFromResource", fhirVersion);
+
+            fromF("direct:metaGetFromServer-%s", fhirVersion)
+                    .toF("fhir-%s://meta/getFromServer?inBody=metaType", fhirVersion);
+
+            fromF("direct:metaGetFromType-%s", fhirVersion)
+                    .toF("fhir-%s://meta/getFromType", fhirVersion);
+
+            // Operation
+            fromF("direct:operationOnInstance-%s", fhirVersion)
+                    .toF("fhir-%s://operation/onInstance", fhirVersion);
+
+            fromF("direct:operationOnInstanceVersion-%s", fhirVersion)
+                    .toF("fhir-%s://operation/onInstanceVersion", fhirVersion);
+
+            fromF("direct:operationOnServer-%s", fhirVersion)
+                    .toF("fhir-%s://operation/onServer", fhirVersion);
+
+            fromF("direct:operationOnType-%s", fhirVersion)
+                    .toF("fhir-%s://operation/onType", fhirVersion);
+
+            fromF("direct:operationProcessMessage-%s", fhirVersion)
+                    .toF("fhir-%s://operation/processMessage", fhirVersion);
+
+            // Patch
+            fromF("direct:patchById-%s", fhirVersion)
+                    .toF("fhir-%s://patch/patchById", fhirVersion);
+
+            fromF("direct:patchBySid-%s", fhirVersion)
+                    .toF("fhir-%s://patch/patchById", fhirVersion);
+
+            fromF("direct:patchByUrl-%s", fhirVersion)
+                    .toF("fhir-%s://patch/patchByUrl", fhirVersion);
+
+            // Read
+            fromF("direct:readById-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByLongId-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByStringId-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByIdAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByLongIdAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByStringIdAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByStringIdAndVersion-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByStringIdAndVersionAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceById", fhirVersion);
+
+            fromF("direct:readByIUrl-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceByUrl", fhirVersion);
+
+            fromF("direct:readByUrl-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceByUrl", fhirVersion);
+
+            fromF("direct:readByStringUrlAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceByUrl", fhirVersion);
+
+            fromF("direct:readByUrlAndStringResource-%s", fhirVersion)
+                    .toF("fhir-%s://read/resourceByUrl", fhirVersion);
+
+            // Search
+            fromF("direct:searchByUrl-%s", fhirVersion)
+                    .toF("fhir-%s://search/searchByUrl?inBody=url", fhirVersion);
+
+            // Transaction
+            fromF("direct:transactionWithBundle-%s", fhirVersion)
+                    .toF("fhir-%s://transaction/withBundle?inBody=bundle", fhirVersion);
+
+            fromF("direct:transactionWithStringBundle-%s", fhirVersion)
+                    .toF("fhir-%s://transaction/withBundle?inBody=stringBundle", fhirVersion);
+
+            fromF("direct:transactionWithResources-%s", fhirVersion)
+                    .toF("fhir-%s://transaction/withResources?inBody=resources", fhirVersion);
+
+            // Update
+            fromF("direct:updateResource-%s", fhirVersion)
+                    .toF("fhir-%s://update/resource", fhirVersion);
+
+            fromF("direct:updateResourceWithStringId-%s", fhirVersion)
+                    .toF("fhir-%s://update/resource", fhirVersion);
+
+            fromF("direct:updateResourceAsString-%s", fhirVersion)
+                    .toF("fhir-%s://update/resource", fhirVersion);
+
+            fromF("direct:updateResourceAsStringWithStringId-%s", fhirVersion)
+                    .toF("fhir-%s://update/resource", fhirVersion);
+
+            fromF("direct:updateResourceBySearchUrl-%s", fhirVersion)
+                    .toF("fhir-%s://update/resourceBySearchUrl", fhirVersion);
+
+            fromF("direct:updateResourceBySearchUrlAndResourceAsString-%s", fhirVersion)
+                    .toF("fhir-%s://update/resourceBySearchUrl", fhirVersion);
+
+            // Validate
+            fromF("direct:validateResource-%s", fhirVersion)
+                    .toF("fhir-%s://validate/resource?inBody=resource", fhirVersion);
+
+            fromF("direct:validateResourceAsString-%s", fhirVersion)
+                    .toF("fhir-%s://validate/resource?inBody=resourceAsString", fhirVersion);
+        }
+    }
+}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirConstants.java
similarity index 74%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirConstants.java
index 27d3862..86c9554 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirConstants.java
@@ -16,9 +16,9 @@
  */
 package org.apache.camel.quarkus.component.fhir.it;
 
-import io.quarkus.test.junit.NativeImageTest;
-
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
-
+public interface FhirConstants {
+    String PATIENT_ADDRESS = "221b Baker St, Marylebone, London NW1 6XE, UK";
+    String PATIENT_FIRST_NAME = "Sherlock";
+    String PATIENT_GENDER_PATCH = "[ { \"op\":\"add\", \"path\":\"/gender\", \"value\":\"female\" } ]";
+    String PATIENT_LAST_NAME = "Holmes";
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Resource.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Resource.java
index 956092d..ea677b5 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Resource.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Resource.java
@@ -17,19 +17,71 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URLEncoder;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
 import javax.inject.Inject;
-import javax.ws.rs.Consumes;
+import javax.inject.Named;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
+import ca.uhn.fhir.model.dstu2.composite.MetaDt;
+import ca.uhn.fhir.model.dstu2.resource.Bundle;
+import ca.uhn.fhir.model.dstu2.resource.Conformance;
+import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
+import ca.uhn.fhir.model.dstu2.resource.Parameters;
+import ca.uhn.fhir.model.dstu2.resource.Patient;
+import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
+import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
+import ca.uhn.fhir.model.dstu2.valueset.NarrativeStatusEnum;
+import ca.uhn.fhir.model.primitive.DateDt;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.model.primitive.StringDt;
+import ca.uhn.fhir.rest.api.CacheControlDirective;
+import ca.uhn.fhir.rest.api.EncodingEnum;
 import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.fhir.FhirComponent;
+import org.apache.camel.component.fhir.api.ExtraParameters;
+import org.apache.camel.component.fhir.internal.FhirHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseMetaType;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_ADDRESS;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_FIRST_NAME;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_LAST_NAME;
 
 @Path("/dstu2")
 @ApplicationScoped
@@ -38,41 +90,1126 @@ public class FhirDstu2Resource {
     @Inject
     ProducerTemplate producerTemplate;
 
-    @Path("/fhir2json")
+    @Inject
+    CamelContext context;
+
+    @Inject
+    @Named("DSTU2")
+    Instance<FhirContext> fhirContextInstance;
+
+    /////////////////////
+    // Capabilities
+    /////////////////////
+
+    @Path("/capabilities")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String capabilities(@QueryParam("encodeAs") String encodeAs) {
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAs.equals("encodeJson") || encodeAs.equals("encodeXml")) {
+            headers.put(encodeAs, Boolean.TRUE);
+        }
+
+        Conformance result = producerTemplate.requestBodyAndHeaders("direct:capabilities-dstu2", Conformance.class,
+                headers, Conformance.class);
+        return result.getStatus();
+    }
+
+    /////////////////////
+    // Create
+    /////////////////////
+
+    @Path("/createPatientAsStringResource")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatientAsStringResource(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address,
+            @QueryParam("encodeAs") String encodeAs) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(Arrays.asList(new StringDt(lastName)));
+
+        String patientString = null;
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(encodeAs, Boolean.TRUE);
+
+        if (encodeAs.equals("encodeJson")) {
+            patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+        } else {
+            patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:createResourceAsString-dstu2", patientString,
+                headers,
+                MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    @Path("/createPatient")
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatient(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(Arrays.asList(new StringDt(lastName)));
+
+        MethodOutcome result = producerTemplate.requestBody("direct:createResource-dstu2", patient, MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    /////////////////////
+    // Dataformats
+    /////////////////////
+
+    @Path("/fhir2json")
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2json(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:json-to-dstu2", patient, InputStream.class)) {
+    public Response fhir2json(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(Arrays.asList(new StringDt(lastName)));
+
+        String patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:json-to-dstu2", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
     @Path("/fhir2xml")
-    @POST
-    @Consumes(MediaType.APPLICATION_XML)
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2xml(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:xml-to-dstu2", patient, InputStream.class)) {
+    public Response fhir2xml(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(Arrays.asList(new StringDt(lastName)));
+
+        String patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:xml-to-dstu2", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
-    @Path("/createPatient")
+    /////////////////////
+    // Delete
+    /////////////////////
+
+    @Path("/deletePatient/byModel")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByModel(@QueryParam("id") String id) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(PATIENT_ADDRESS);
+        patient.addName().addGiven(PATIENT_FIRST_NAME).setFamily(Arrays.asList(new StringDt(PATIENT_LAST_NAME)));
+        patient.setId(id);
+
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:delete-dstu2", patient,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byId")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientById(@QueryParam("id") String id) {
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:deleteById-dstu2",
+                new IdDt(id),
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byIdPart")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByIdPart(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.type", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteByStringId-dstu2", null, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byUrl")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByUrl(@QueryParam("cache") boolean noCache) {
+        Map<String, Object> headers = new HashMap<>();
+        if (noCache) {
+            headers.put(ExtraParameters.CACHE_CONTROL_DIRECTIVE.getHeaderName(), new CacheControlDirective().setNoCache(true));
+        }
+
+        String body = String.format("Patient?given=%s&family=%s", PATIENT_FIRST_NAME, PATIENT_LAST_NAME);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteConditionalByUrl-dstu2", body,
+                headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // History
+    /////////////////////
+
+    @Path("/history/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnInstance(@QueryParam("id") String id) {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", new IdDt(id));
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnInstance-dstu2", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnServer-dstu2", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnType() {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnType-dstu2", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Load page
+    /////////////////////
+
+    @Path("/load/page/byUrl")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageByUrl() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.url", nextPageLink);
+        headers.put("CamelFhir.returnType", Bundle.class);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPageByUrl-dstu2", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/next")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageNext() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        Bundle result = producerTemplate.requestBody("direct:loadPageNext-dstu2", bundle, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/previous")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPagePrevious(@QueryParam("encodeAsXml") boolean encodeAsXml) {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+        bundle = getFhirClient()
+                .loadPage()
+                .byUrl(nextPageLink)
+                .andReturnBundle(Bundle.class)
+                .execute();
+
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAsXml) {
+            headers.put(ExtraParameters.ENCODING_ENUM.getHeaderName(), EncodingEnum.XML);
+        }
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPagePrevious-dstu2", bundle, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Meta
+    /////////////////////
+
+    @Path("/meta")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaAdd(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+        MetaDt inMeta = new MetaDt();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaAdd-dstu2", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaDelete(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+        MetaDt inMeta = new MetaDt();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaDelete-dstu2", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromResource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromResource(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", MetaDt.class);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromResource-dstu2", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromServer() {
+        MetaDt result = producerTemplate.requestBody("direct:metaGetFromServer-dstu2", MetaDt.class,
+                MetaDt.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromType(@QueryParam("preferResponseType") boolean preferResponseType) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", MetaDt.class);
+        headers.put("CamelFhir.resourceType", "Patient");
+
+        if (preferResponseType) {
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPE.getHeaderName(), Patient.class);
+        }
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromType-dstu2", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    /////////////////////
+    // Operation
+    /////////////////////
+
+    @Path("/operation/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstance(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstance-dstu2", null, headers,
+                Parameters.class);
+
+        Parameters.Parameter parameter = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parameter.getResource();
+        IdDt patientId = bundle.getEntry().get(0).getResource().getId();
+        return patientId.toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onInstanceVersion")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstanceVersion(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstanceVersion-dstu2", null, headers,
+                Parameters.class);
+
+        Parameters.Parameter parameter = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parameter.getResource();
+        IdDt patientId = bundle.getEntry().get(0).getResource().getId();
+        return patientId.toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public boolean operationOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.name", "$get-resource-counts");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.TRUE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnServer-dstu2", null, headers,
+                Parameters.class);
+        return result != null;
+    }
+
+    @Path("/operation/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnType() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnType-dstu2", null, headers,
+                Parameters.class);
+
+        Parameters.Parameter parameter = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parameter.getResource();
+        IdDt patientId = bundle.getEntry().get(0).getResource().getId();
+        return patientId.toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/processMessage")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationProcessMessage() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.respondToUri", null);
+        headers.put("CamelFhir.msgBundle", null);
+        headers.put("CamelFhir.asynchronous", Boolean.FALSE);
+        headers.put("CamelFhir.responseClass", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        IBaseBundle result = producerTemplate.requestBodyAndHeaders("direct:operationProcessMessage-dstu2", null, headers,
+                IBaseBundle.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // Patch
+    /////////////////////
+
+    @Path("/patch/byId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchById(@QueryParam("id") String id, String patch) {
+        IdDt iIdType = new IdDt(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchById-dstu2", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender();
+    }
+
+    @Path("/patch/byStringId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByStringId(
+            @QueryParam("id") String id,
+            @QueryParam("preferResponseTypes") boolean preferResponseTypes,
+            String patch) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        if (preferResponseTypes) {
+            List<Class<? extends IBaseResource>> preferredResponseTypes = new ArrayList<>();
+            preferredResponseTypes.add(Patient.class);
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPES.getHeaderName(), preferredResponseTypes);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchBySid-dstu2", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender();
+    }
+
+    @Path("/patch/byUrl")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByUrl(@QueryParam("id") String id, String patch) throws UnsupportedEncodingException {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.url", "Patient?" + Patient.SP_RES_ID + "=" + id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchByUrl-dstu2", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender();
+    }
+
+    /////////////////////
+    // Read
+    /////////////////////
+
+    @Path("/readPatient/byId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientById(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.id", new IdDt(id));
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readById-dstu2", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongId-dstu2", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringId-dstu2", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIdAndStringResource(@QueryParam("id") String id) {
+        IdDt iIdType = new IdDt(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.id", iIdType);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIdAndStringResource-dstu2", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongIdAndStringResource-dstu2", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndStringResource-dstu2", null,
+                    headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersion")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersion(@QueryParam("id") String id, @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersion-dstu2", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersionWithResourceClass")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersionWithResourceClass(@QueryParam("id") String id,
+            @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersionAndStringResource-dstu2",
+                    null,
+                    headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.iUrl", new IdDt(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIUrl-dstu2", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.url", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrl-dstu2", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringUrlAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.iUrl", new IdDt(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringUrlAndStringResource-dstu2", null,
+                    headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readByUrlAndStringResource(@QueryParam("id") String id, @QueryParam("prettyPrint") boolean prettyPrint) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.url", id);
+
+        if (prettyPrint) {
+            headers.put(ExtraParameters.PRETTY_PRINT.getHeaderName(), Boolean.TRUE);
+        }
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrlAndStringResource-dstu2", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    /////////////////////
+    // Search
+    /////////////////////
+
+    @Path("/search/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response searchByUrl(@QueryParam("id") String id) {
+        String url = "Patient?" + Patient.SP_RES_ID + "=" + id + "&_format=json";
+        Bundle result = producerTemplate.requestBody("direct:searchByUrl-dstu2", url, Bundle.class);
+
+        List<Bundle.Entry> entry = result.getEntry();
+        if (ObjectHelper.isNotEmpty(entry)) {
+            Patient patient = (Patient) entry.get(0).getResource();
+            return Response.ok().entity(patientToJsonObject(patient)).build();
+        }
+        return Response.status(404).build();
+    }
+
+    /////////////////////
+    // Transaction
+    /////////////////////
+
+    @Path("/transaction/withBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithBundle() {
+        Bundle result = producerTemplate.requestBody("direct:transactionWithBundle-dstu2", createTransactionBundle(),
+                Bundle.class);
+        return result.getEntry().get(0).getResponse().getStatus();
+    }
+
+    @Path("/transaction/withStringBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithStringBundle() {
+        Bundle transactionBundle = createTransactionBundle();
+        String stringBundle = fhirContextInstance.get().newJsonParser().encodeResourceToString(transactionBundle);
+        return producerTemplate.requestBody("direct:transactionWithStringBundle-dstu2", stringBundle, String.class);
+    }
+
+    @Path("/transaction/withResources")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @SuppressWarnings("unchecked")
+    public int transactionWithResources(@QueryParam("summaryEnum") boolean summaryEnum) {
+        Patient oscar = new Patient()
+                .addName(new HumanNameDt().addGiven("Oscar").setFamily(Arrays.asList(new StringDt("Peterson"))));
+        Patient bobbyHebb = new Patient()
+                .addName(new HumanNameDt().addGiven("Bobby").setFamily(Arrays.asList(new StringDt("Hebb"))));
+        List<IBaseResource> patients = new ArrayList<>(2);
+        patients.add(oscar);
+        patients.add(bobbyHebb);
+
+        Map<String, Object> headers = new HashMap<>();
+        if (summaryEnum) {
+            headers.put(ExtraParameters.SUMMARY_ENUM.getHeaderName(), SummaryEnum.DATA);
+        }
+
+        List<IBaseResource> result = producerTemplate.requestBodyAndHeaders("direct:transactionWithResources-dstu2", patients,
+                headers, List.class);
+        return result.size();
+    }
+
+    /////////////////////
+    // Update
+    /////////////////////
+
+    @Path("/update/resource")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response createPatient(String patient) throws Exception {
-        MethodOutcome result = producerTemplate.requestBody("direct:create-dstu2", patient, MethodOutcome.class);
-        return Response
-                .created(new URI("https://camel.apache.org/"))
-                .entity(result.getId().getIdPart())
-                .build();
+    public void updateResource(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-dstu2", null, headers);
+    }
+
+    @Path("/update/resource/withoutId")
+    @POST
+    public void updateResourceWithoutId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-dstu2", null, headers);
+    }
+
+    @Path("/update/resource/withStringId")
+    @POST
+    public void updateResourceWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceWithStringId-dstu2", null, headers);
+    }
+
+    @Path("/update/resource/asString")
+    @POST
+    public void updateResourceAsString(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsString-dstu2", null, headers);
+    }
+
+    @Path("/update/resource/asStringWithStringId")
+    @POST
+    public void updateResourceAsStringWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsStringWithStringId-dstu2", null, headers);
+    }
+
+    @Path("/update/resource/bySearchUrl")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceBySearchUrl(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getIdElement().getIdPart(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrl-dstu2", null, headers,
+                MethodOutcome.class);
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    @Path("/update/resource/bySearchUrlAndResourceAsString")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceByUrlAndResourceAsString(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(new DateDt(date));
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getId().toString(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders(
+                "direct:updateResourceBySearchUrlAndResourceAsString-dstu2",
+                null, headers, MethodOutcome.class);
+
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    /////////////////////
+    // Validate
+    /////////////////////
+
+    @Path("/validate/resource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResource() {
+        Patient patient = new Patient()
+                .addName(new HumanNameDt()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(Arrays.asList(new StringDt(PATIENT_LAST_NAME))));
+
+        patient.getText().setStatus(NarrativeStatusEnum.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResource-dstu2", patient, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    @Path("/validate/resourceAsString")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResourceAsString() {
+        Patient patient = new Patient()
+                .addName(new HumanNameDt()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(Arrays.asList(new StringDt(PATIENT_LAST_NAME))));
+
+        patient.getText().setStatus(NarrativeStatusEnum.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        String body = this.fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResourceAsString-dstu2", body, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    private JsonObject patientToJsonObject(Patient patient) {
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("address", patient.getAddress().get(0).getLine().get(0).getValueAsString());
+        builder.add("firstName", patient.getName().get(0).getGiven().get(0).getValueAsString());
+        builder.add("lastName", patient.getName().get(0).getFamily().get(0).getValueAsString());
+
+        Date birthDate = patient.getBirthDate();
+        if (birthDate != null) {
+            String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(birthDate);
+            builder.add("birthDate", formattedDate);
+        }
+        return builder.build();
+    }
+
+    private Bundle createTransactionBundle() {
+        Bundle input = new Bundle();
+        input.setType(BundleTypeEnum.TRANSACTION);
+        input.addEntry()
+                .setResource(new Patient()
+                        .addName(new HumanNameDt().addGiven("Art").setFamily(Arrays.asList(new StringDt("Tatum")))))
+                .getRequest()
+                .setMethod(HTTPVerbEnum.POST);
+        return input;
+    }
+
+    private IGenericClient getFhirClient() {
+        FhirComponent component = context.getComponent("fhir-dstu2", FhirComponent.class);
+        return FhirHelper.createClient(component.getConfiguration(), context);
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2RouteBuilder.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2RouteBuilder.java
index a26b4f6..c37d848d5 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2RouteBuilder.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2RouteBuilder.java
@@ -22,14 +22,10 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.parser.StrictErrorHandler;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.fhir.FhirJsonDataFormat;
-import org.apache.camel.component.fhir.FhirXmlDataFormat;
 import org.apache.camel.quarkus.component.fhir.FhirFlags;
 
 @ApplicationScoped
-public class FhirDstu2RouteBuilder extends RouteBuilder {
+public class FhirDstu2RouteBuilder extends AbstractFhirRouteBuilder {
 
     private static final Boolean ENABLED = new FhirFlags.Dstu2Enabled().getAsBoolean();
 
@@ -38,29 +34,17 @@ public class FhirDstu2RouteBuilder extends RouteBuilder {
     Instance<FhirContext> fhirContextInstance;
 
     @Override
-    public void configure() {
-        if (ENABLED) {
-            FhirContext fhirContext = fhirContextInstance.get();
-            fhirContext.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirJsonDataFormat fhirJsonDataFormat = new FhirJsonDataFormat();
-            fhirJsonDataFormat.setFhirContext(fhirContext);
-            fhirJsonDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirXmlDataFormat fhirXmlDataFormat = new FhirXmlDataFormat();
-            fhirXmlDataFormat.setFhirContext(fhirContext);
-            fhirXmlDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            from("direct:json-to-dstu2")
-                    .unmarshal(fhirJsonDataFormat)
-                    .marshal(fhirJsonDataFormat);
+    String getFhirVersion() {
+        return "dstu2";
+    }
 
-            from("direct:xml-to-dstu2")
-                    .unmarshal(fhirXmlDataFormat)
-                    .marshal(fhirXmlDataFormat);
+    @Override
+    FhirContext getFhirContext() {
+        return fhirContextInstance.get();
+    }
 
-            from("direct:create-dstu2")
-                    .to("fhir://create/resource?inBody=resourceAsString&fhirContext=#DSTU2");
-        }
+    @Override
+    boolean isEnabled() {
+        return ENABLED;
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Resource.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Resource.java
index 6fd84ed..8abad66 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Resource.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Resource.java
@@ -17,19 +17,66 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URLEncoder;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
 import javax.inject.Inject;
-import javax.ws.rs.Consumes;
+import javax.inject.Named;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.api.CacheControlDirective;
+import ca.uhn.fhir.rest.api.EncodingEnum;
 import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.fhir.FhirComponent;
+import org.apache.camel.component.fhir.api.ExtraParameters;
+import org.apache.camel.component.fhir.internal.FhirHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.hl7.fhir.dstu3.model.Bundle;
+import org.hl7.fhir.dstu3.model.CapabilityStatement;
+import org.hl7.fhir.dstu3.model.HumanName;
+import org.hl7.fhir.dstu3.model.IdType;
+import org.hl7.fhir.dstu3.model.Meta;
+import org.hl7.fhir.dstu3.model.Narrative;
+import org.hl7.fhir.dstu3.model.OperationOutcome;
+import org.hl7.fhir.dstu3.model.Parameters;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseMetaType;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_ADDRESS;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_FIRST_NAME;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_LAST_NAME;
 
 @Path("/dstu3")
 @ApplicationScoped
@@ -38,41 +85,1124 @@ public class FhirDstu3Resource {
     @Inject
     ProducerTemplate producerTemplate;
 
-    @Path("/fhir2json")
+    @Inject
+    CamelContext context;
+
+    @Inject
+    @Named("DSTU3")
+    Instance<FhirContext> fhirContextInstance;
+
+    /////////////////////
+    // Capabilities
+    /////////////////////
+
+    @Path("/capabilities")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String capabilities(@QueryParam("encodeAs") String encodeAs) {
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAs.equals("encodeJson") || encodeAs.equals("encodeXml")) {
+            headers.put(encodeAs, Boolean.TRUE);
+        }
+
+        CapabilityStatement result = producerTemplate.requestBodyAndHeaders("direct:capabilities-dstu3",
+                CapabilityStatement.class,
+                headers, CapabilityStatement.class);
+        return result.getStatus().name();
+    }
+
+    /////////////////////
+    // Create
+    /////////////////////
+
+    @Path("/createPatientAsStringResource")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatientAsStringResource(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address,
+            @QueryParam("encodeAs") String encodeAs) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = null;
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(encodeAs, Boolean.TRUE);
+
+        if (encodeAs.equals("encodeJson")) {
+            patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+        } else {
+            patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:createResourceAsString-dstu3", patientString,
+                headers,
+                MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    @Path("/createPatient")
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatient(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        MethodOutcome result = producerTemplate.requestBody("direct:createResource-dstu3", patient, MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    /////////////////////
+    // Dataformats
+    /////////////////////
+
+    @Path("/fhir2json")
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2json(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:json-to-dstu3", patient, InputStream.class)) {
+    public Response fhir2json(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:json-to-dstu3", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
     @Path("/fhir2xml")
-    @POST
-    @Consumes(MediaType.APPLICATION_XML)
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2xml(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:xml-to-dstu3", patient, InputStream.class)) {
+    public Response fhir2xml(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:xml-to-dstu3", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
-    @Path("/createPatient")
+    /////////////////////
+    // Delete
+    /////////////////////
+
+    @Path("/deletePatient/byModel")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByModel(@QueryParam("id") String id) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(PATIENT_ADDRESS);
+        patient.addName().addGiven(PATIENT_FIRST_NAME).setFamily(PATIENT_LAST_NAME);
+        patient.setId(id);
+
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:delete-dstu3", patient,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byId")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientById(@QueryParam("id") String id) {
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:deleteById-dstu3", new IdType(id),
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byIdPart")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByIdPart(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.type", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteByStringId-dstu3", null, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byUrl")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByUrl(@QueryParam("cache") boolean noCache) {
+        Map<String, Object> headers = new HashMap<>();
+        if (noCache) {
+            headers.put(ExtraParameters.CACHE_CONTROL_DIRECTIVE.getHeaderName(), new CacheControlDirective().setNoCache(true));
+        }
+
+        String body = String.format("Patient?given=%s&family=%s", PATIENT_FIRST_NAME, PATIENT_LAST_NAME);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteConditionalByUrl-dstu3", body,
+                headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // History
+    /////////////////////
+
+    @Path("/history/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnInstance(@QueryParam("id") String id) {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", new IdType(id));
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnInstance-dstu3", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnServer-dstu3", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnType() {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnType-dstu3", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Load page
+    /////////////////////
+
+    @Path("/load/page/byUrl")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageByUrl() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.url", nextPageLink);
+        headers.put("CamelFhir.returnType", Bundle.class);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPageByUrl-dstu3", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/next")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageNext() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        Bundle result = producerTemplate.requestBody("direct:loadPageNext-dstu3", bundle, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/previous")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPagePrevious(@QueryParam("encodeAsXml") boolean encodeAsXml) {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+        bundle = getFhirClient()
+                .loadPage()
+                .byUrl(nextPageLink)
+                .andReturnBundle(Bundle.class)
+                .execute();
+
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAsXml) {
+            headers.put(ExtraParameters.ENCODING_ENUM.getHeaderName(), EncodingEnum.XML);
+        }
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPagePrevious-dstu3", bundle, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Meta
+    /////////////////////
+
+    @Path("/meta")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response createPatient(String patient) throws Exception {
-        MethodOutcome result = producerTemplate.requestBody("direct:create-dstu3", patient, MethodOutcome.class);
-        return Response
-                .created(new URI("https://camel.apache.org/"))
-                .entity(result.getId().getIdPart())
-                .build();
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaAdd(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaAdd-dstu3", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaDelete(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaDelete-dstu3", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromResource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromResource(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromResource-dstu3", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromServer() {
+        IBaseMetaType result = producerTemplate.requestBody("direct:metaGetFromServer-dstu3", Meta.class, IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromType(@QueryParam("preferResponseType") boolean preferResponseType) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.resourceType", "Patient");
+
+        if (preferResponseType) {
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPE.getHeaderName(), Patient.class);
+        }
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromType-dstu3", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    /////////////////////
+    // Operation
+    /////////////////////
+
+    @Path("/operation/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstance(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstance-dstu3", null, headers,
+                Parameters.class);
+
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onInstanceVersion")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstanceVersion(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstanceVersion-dstu3", null, headers,
+                Parameters.class);
+
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public boolean operationOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.name", "$get-resource-counts");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.TRUE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnServer-dstu3", null, headers,
+                Parameters.class);
+        return result != null;
+    }
+
+    @Path("/operation/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnType() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnType-dstu3", null, headers,
+                Parameters.class);
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/processMessage")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationProcessMessage() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.respondToUri", null);
+        headers.put("CamelFhir.msgBundle", null);
+        headers.put("CamelFhir.asynchronous", Boolean.FALSE);
+        headers.put("CamelFhir.responseClass", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        IBaseBundle result = producerTemplate.requestBodyAndHeaders("direct:operationProcessMessage-dstu3", null, headers,
+                IBaseBundle.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // Patch
+    /////////////////////
+
+    @Path("/patch/byId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchById(@QueryParam("id") String id, String patch) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchById-dstu3", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byStringId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByStringId(
+            @QueryParam("id") String id,
+            @QueryParam("preferResponseTypes") boolean preferResponseTypes,
+            String patch) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        if (preferResponseTypes) {
+            List<Class<? extends IBaseResource>> preferredResponseTypes = new ArrayList<>();
+            preferredResponseTypes.add(Patient.class);
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPES.getHeaderName(), preferredResponseTypes);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchBySid-dstu3", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byUrl")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByUrl(@QueryParam("id") String id, String patch) throws UnsupportedEncodingException {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.url", "Patient?" + Patient.SP_RES_ID + "=" + id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchByUrl-dstu3", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    /////////////////////
+    // Read
+    /////////////////////
+
+    @Path("/readPatient/byId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientById(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.id", new IdType(id));
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readById-dstu3", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongId-dstu3", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringId-dstu3", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIdAndStringResource(@QueryParam("id") String id) {
+        IdType idType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.id", idType);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIdAndStringResource-dstu3", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongIdAndStringResource-dstu3", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndStringResource-dstu3", null,
+                    headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersion")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersion(@QueryParam("id") String id, @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersion-dstu3", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersionWithResourceClass")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersionWithResourceClass(@QueryParam("id") String id,
+            @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersionAndStringResource-dstu3",
+                    null,
+                    headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIUrl-dstu3", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.url", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrl-dstu3", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringUrlAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringUrlAndStringResource-dstu3", null,
+                    headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readByUrlAndStringResource(@QueryParam("id") String id, @QueryParam("prettyPrint") boolean prettyPrint) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.url", id);
+
+        if (prettyPrint) {
+            headers.put(ExtraParameters.PRETTY_PRINT.getHeaderName(), Boolean.TRUE);
+        }
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrlAndStringResource-dstu3", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    /////////////////////
+    // Search
+    /////////////////////
+
+    @Path("/search/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response searchByUrl(@QueryParam("id") String id) {
+        String url = "Patient?" + Patient.SP_RES_ID + "=" + id + "&_format=json";
+        Bundle result = producerTemplate.requestBody("direct:searchByUrl-dstu3", url, Bundle.class);
+
+        List<Bundle.BundleEntryComponent> entry = result.getEntry();
+        if (ObjectHelper.isNotEmpty(entry)) {
+            Patient patient = (Patient) entry.get(0).getResource();
+            return Response.ok().entity(patientToJsonObject(patient)).build();
+        }
+        return Response.status(404).build();
+    }
+
+    /////////////////////
+    // Transaction
+    /////////////////////
+
+    @Path("/transaction/withBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithBundle() {
+        Bundle result = producerTemplate.requestBody("direct:transactionWithBundle-dstu3", createTransactionBundle(),
+                Bundle.class);
+        return result.getEntry().get(0).getResponse().getStatus();
+    }
+
+    @Path("/transaction/withStringBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithStringBundle() {
+        Bundle transactionBundle = createTransactionBundle();
+        String stringBundle = fhirContextInstance.get().newJsonParser().encodeResourceToString(transactionBundle);
+        return producerTemplate.requestBody("direct:transactionWithStringBundle-dstu3", stringBundle, String.class);
+    }
+
+    @Path("/transaction/withResources")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @SuppressWarnings("unchecked")
+    public int transactionWithResources(@QueryParam("summaryEnum") boolean summaryEnum) {
+        Patient oscar = new Patient().addName(new HumanName().addGiven("Oscar").setFamily("Peterson"));
+        Patient bobbyHebb = new Patient().addName(new HumanName().addGiven("Bobby").setFamily("Hebb"));
+        List<IBaseResource> patients = new ArrayList<>(2);
+        patients.add(oscar);
+        patients.add(bobbyHebb);
+
+        Map<String, Object> headers = new HashMap<>();
+        if (summaryEnum) {
+            headers.put(ExtraParameters.SUMMARY_ENUM.getHeaderName(), SummaryEnum.DATA);
+        }
+
+        List<IBaseResource> result = producerTemplate.requestBodyAndHeaders("direct:transactionWithResources-dstu3", patients,
+                headers, List.class);
+        return result.size();
+    }
+
+    /////////////////////
+    // Update
+    /////////////////////
+
+    @Path("/update/resource")
+    @POST
+    public void updateResource(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-dstu3", null, headers);
+    }
+
+    @Path("/update/resource/withoutId")
+    @POST
+    public void updateResourceWithoutId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-dstu3", null, headers);
+    }
+
+    @Path("/update/resource/withStringId")
+    @POST
+    public void updateResourceWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceWithStringId-dstu3", null, headers);
+    }
+
+    @Path("/update/resource/asString")
+    @POST
+    public void updateResourceAsString(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsString-dstu3", null, headers);
+    }
+
+    @Path("/update/resource/asStringWithStringId")
+    @POST
+    public void updateResourceAsStringWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsStringWithStringId-dstu3", null, headers);
+    }
+
+    @Path("/update/resource/bySearchUrl")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceBySearchUrl(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getIdElement().getIdPart(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrl-dstu3", null, headers,
+                MethodOutcome.class);
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    @Path("/update/resource/bySearchUrlAndResourceAsString")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceByUrlAndResourceAsString(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getId(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders(
+                "direct:updateResourceBySearchUrlAndResourceAsString-dstu3",
+                null, headers, MethodOutcome.class);
+
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    /////////////////////
+    // Validate
+    /////////////////////
+
+    @Path("/validate/resource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResource() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResource-dstu3", patient, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    @Path("/validate/resourceAsString")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResourceAsString() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        String body = this.fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResourceAsString-dstu3", body, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    private JsonObject patientToJsonObject(Patient patient) {
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("address", patient.getAddress().get(0).getLine().get(0).asStringValue());
+        builder.add("firstName", patient.getName().get(0).getGiven().get(0).asStringValue());
+        builder.add("lastName", patient.getName().get(0).getFamily());
+
+        Date birthDate = patient.getBirthDate();
+        if (birthDate != null) {
+            String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(birthDate);
+            builder.add("birthDate", formattedDate);
+        }
+        return builder.build();
+    }
+
+    private Bundle createTransactionBundle() {
+        Bundle input = new Bundle();
+        input.setType(Bundle.BundleType.TRANSACTION);
+        input.addEntry()
+                .setResource(new Patient().addName(new HumanName().addGiven("Art").setFamily("Tatum")))
+                .getRequest()
+                .setMethod(Bundle.HTTPVerb.POST);
+        return input;
+    }
+
+    private IGenericClient getFhirClient() {
+        FhirComponent component = context.getComponent("fhir-dstu3", FhirComponent.class);
+        return FhirHelper.createClient(component.getConfiguration(), context);
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3RouteBuilder.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3RouteBuilder.java
index b08ba71..ad3de40 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3RouteBuilder.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3RouteBuilder.java
@@ -22,14 +22,10 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.parser.StrictErrorHandler;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.fhir.FhirJsonDataFormat;
-import org.apache.camel.component.fhir.FhirXmlDataFormat;
 import org.apache.camel.quarkus.component.fhir.FhirFlags;
 
 @ApplicationScoped
-public class FhirDstu3RouteBuilder extends RouteBuilder {
+public class FhirDstu3RouteBuilder extends AbstractFhirRouteBuilder {
 
     private static final Boolean ENABLED = new FhirFlags.Dstu3Enabled().getAsBoolean();
     @Inject
@@ -37,29 +33,17 @@ public class FhirDstu3RouteBuilder extends RouteBuilder {
     Instance<FhirContext> fhirContextInstance;
 
     @Override
-    public void configure() {
-        if (ENABLED) {
-            FhirContext fhirContext = fhirContextInstance.get();
-            fhirContext.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirJsonDataFormat fhirJsonDataFormat = new FhirJsonDataFormat();
-            fhirJsonDataFormat.setFhirContext(fhirContext);
-            fhirJsonDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirXmlDataFormat fhirXmlDataFormat = new FhirXmlDataFormat();
-            fhirXmlDataFormat.setFhirContext(fhirContext);
-            fhirXmlDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            from("direct:json-to-dstu3")
-                    .unmarshal(fhirJsonDataFormat)
-                    .marshal(fhirJsonDataFormat);
+    String getFhirVersion() {
+        return "dstu3";
+    }
 
-            from("direct:xml-to-dstu3")
-                    .unmarshal(fhirXmlDataFormat)
-                    .marshal(fhirXmlDataFormat);
+    @Override
+    FhirContext getFhirContext() {
+        return fhirContextInstance.get();
+    }
 
-            from("direct:create-dstu3")
-                    .to("fhir://create/resource?inBody=resourceAsString&fhirContext=#DSTU3");
-        }
+    @Override
+    boolean isEnabled() {
+        return ENABLED;
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Resource.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Resource.java
index 433c520..ab7e23e 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Resource.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Resource.java
@@ -17,19 +17,68 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URLEncoder;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
 import javax.inject.Inject;
-import javax.ws.rs.Consumes;
+import javax.inject.Named;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.api.CacheControlDirective;
+import ca.uhn.fhir.rest.api.EncodingEnum;
 import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.fhir.FhirComponent;
+import org.apache.camel.component.fhir.api.ExtraParameters;
+import org.apache.camel.component.fhir.internal.FhirHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseMetaType;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.Bundle;
+import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
+import org.hl7.fhir.r4.model.CapabilityStatement;
+import org.hl7.fhir.r4.model.HumanName;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Meta;
+import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
+import org.hl7.fhir.r4.model.OperationOutcome;
+import org.hl7.fhir.r4.model.Parameters;
+import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent;
+import org.hl7.fhir.r4.model.Patient;
+
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_ADDRESS;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_FIRST_NAME;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_LAST_NAME;
 
 @Path("/r4")
 @ApplicationScoped
@@ -38,41 +87,1115 @@ public class FhirR4Resource {
     @Inject
     ProducerTemplate producerTemplate;
 
-    @Path("/fhir2json")
+    @Inject
+    CamelContext context;
+
+    @Inject
+    @Named("R4")
+    Instance<FhirContext> fhirContextInstance;
+
+    /////////////////////
+    // Capabilities
+    /////////////////////
+
+    @Path("/capabilities")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String capabilities(@QueryParam("encodeAs") String encodeAs) {
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAs.equals("encodeJson") || encodeAs.equals("encodeXml")) {
+            headers.put(encodeAs, Boolean.TRUE);
+        }
+
+        CapabilityStatement result = producerTemplate.requestBodyAndHeaders("direct:capabilities-r4", CapabilityStatement.class,
+                headers, CapabilityStatement.class);
+        return result.getStatus().name();
+    }
+
+    /////////////////////
+    // Create
+    /////////////////////
+
+    @Path("/createPatientAsStringResource")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatientAsStringResource(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address,
+            @QueryParam("encodeAs") String encodeAs) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = null;
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(encodeAs, Boolean.TRUE);
+
+        if (encodeAs.equals("encodeJson")) {
+            patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+        } else {
+            patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:createResourceAsString-r4", patientString,
+                headers,
+                MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    @Path("/createPatient")
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatient(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        MethodOutcome result = producerTemplate.requestBody("direct:createResource-r4", patient, MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    /////////////////////
+    // Dataformats
+    /////////////////////
+
+    @Path("/fhir2json")
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2json(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:json-to-r4", patient, InputStream.class)) {
+    public Response fhir2json(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:json-to-r4", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
     @Path("/fhir2xml")
-    @POST
-    @Consumes(MediaType.APPLICATION_XML)
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2xml(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:xml-to-r4", patient, InputStream.class)) {
+    public Response fhir2xml(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:xml-to-r4", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
-    @Path("/createPatient")
+    /////////////////////
+    // Delete
+    /////////////////////
+
+    @Path("/deletePatient/byModel")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByModel(@QueryParam("id") String id) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(PATIENT_ADDRESS);
+        patient.addName().addGiven(PATIENT_FIRST_NAME).setFamily(PATIENT_LAST_NAME);
+        patient.setId(id);
+
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:delete-r4", patient, IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byId")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientById(@QueryParam("id") String id) {
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:deleteById-r4", new IdType(id),
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byIdPart")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByIdPart(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.type", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteByStringId-r4", null, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byUrl")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByUrl(@QueryParam("cache") boolean noCache) {
+        Map<String, Object> headers = new HashMap<>();
+        if (noCache) {
+            headers.put(ExtraParameters.CACHE_CONTROL_DIRECTIVE.getHeaderName(), new CacheControlDirective().setNoCache(true));
+        }
+
+        String body = String.format("Patient?given=%s&family=%s", PATIENT_FIRST_NAME, PATIENT_LAST_NAME);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteConditionalByUrl-r4", body, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // History
+    /////////////////////
+
+    @Path("/history/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnInstance(@QueryParam("id") String id) {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", new IdType(id));
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnInstance-r4", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnServer-r4", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnType() {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnType-r4", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Load page
+    /////////////////////
+
+    @Path("/load/page/byUrl")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageByUrl() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.url", nextPageLink);
+        headers.put("CamelFhir.returnType", Bundle.class);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPageByUrl-r4", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/next")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageNext() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        Bundle result = producerTemplate.requestBody("direct:loadPageNext-r4", bundle, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/previous")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPagePrevious(@QueryParam("encodeAsXml") boolean encodeAsXml) {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+        bundle = getFhirClient()
+                .loadPage()
+                .byUrl(nextPageLink)
+                .andReturnBundle(Bundle.class)
+                .execute();
+
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAsXml) {
+            headers.put(ExtraParameters.ENCODING_ENUM.getHeaderName(), EncodingEnum.XML);
+        }
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPagePrevious-r4", bundle, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Meta
+    /////////////////////
+
+    @Path("/meta")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response createPatient(String patient) throws Exception {
-        MethodOutcome result = producerTemplate.requestBody("direct:create-r4", patient, MethodOutcome.class);
-        return Response
-                .created(new URI("https://camel.apache.org/"))
-                .entity(result.getId().getIdPart())
-                .build();
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaAdd(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaAdd-r4", null, headers, IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaDelete(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaDelete-r4", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromResource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromResource(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromResource-r4", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromServer() {
+        IBaseMetaType result = producerTemplate.requestBody("direct:metaGetFromServer-r4", Meta.class, IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromType(@QueryParam("preferResponseType") boolean preferResponseType) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.resourceType", "Patient");
+
+        if (preferResponseType) {
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPE.getHeaderName(), Patient.class);
+        }
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromType-r4", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    /////////////////////
+    // Operation
+    /////////////////////
+
+    @Path("/operation/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstance(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstance-r4", null, headers,
+                Parameters.class);
+
+        ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onInstanceVersion")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstanceVersion(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstanceVersion-r4", null, headers,
+                Parameters.class);
+
+        ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public boolean operationOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.name", "$get-resource-counts");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.TRUE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnServer-r4", null, headers,
+                Parameters.class);
+        return result != null;
+    }
+
+    @Path("/operation/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnType() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnType-r4", null, headers,
+                Parameters.class);
+        ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/processMessage")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationProcessMessage() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.respondToUri", null);
+        headers.put("CamelFhir.msgBundle", null);
+        headers.put("CamelFhir.asynchronous", Boolean.FALSE);
+        headers.put("CamelFhir.responseClass", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        IBaseBundle result = producerTemplate.requestBodyAndHeaders("direct:operationProcessMessage-r4", null, headers,
+                IBaseBundle.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // Patch
+    /////////////////////
+
+    @Path("/patch/byId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchById(@QueryParam("id") String id, String patch) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchById-r4", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byStringId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByStringId(
+            @QueryParam("id") String id,
+            @QueryParam("preferResponseTypes") boolean preferResponseTypes,
+            String patch) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        if (preferResponseTypes) {
+            List<Class<? extends IBaseResource>> preferredResponseTypes = new ArrayList<>();
+            preferredResponseTypes.add(Patient.class);
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPES.getHeaderName(), preferredResponseTypes);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchBySid-r4", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byUrl")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByUrl(@QueryParam("id") String id, String patch) throws UnsupportedEncodingException {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.url", "Patient?" + Patient.SP_RES_ID + "=" + id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchByUrl-r4", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    /////////////////////
+    // Read
+    /////////////////////
+
+    @Path("/readPatient/byId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientById(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.id", new IdType(id));
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readById-r4", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongId-r4", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringId-r4", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIdAndStringResource(@QueryParam("id") String id) {
+        IdType idType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.id", idType);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIdAndStringResource-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongIdAndStringResource-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndStringResource-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersion")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersion(@QueryParam("id") String id, @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersion-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersionWithResourceClass")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersionWithResourceClass(@QueryParam("id") String id,
+            @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersionAndStringResource-r4", null,
+                    headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIUrl-r4", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.url", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrl-r4", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringUrlAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringUrlAndStringResource-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readByUrlAndStringResource(@QueryParam("id") String id, @QueryParam("prettyPrint") boolean prettyPrint) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.url", id);
+
+        if (prettyPrint) {
+            headers.put(ExtraParameters.PRETTY_PRINT.getHeaderName(), Boolean.TRUE);
+        }
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrlAndStringResource-r4", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    /////////////////////
+    // Search
+    /////////////////////
+
+    @Path("/search/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response searchByUrl(@QueryParam("id") String id) {
+        String url = "Patient?" + Patient.SP_RES_ID + "=" + id + "&_format=json";
+        Bundle result = producerTemplate.requestBody("direct:searchByUrl-r4", url, Bundle.class);
+
+        List<BundleEntryComponent> entry = result.getEntry();
+        if (ObjectHelper.isNotEmpty(entry)) {
+            Patient patient = (Patient) entry.get(0).getResource();
+            return Response.ok().entity(patientToJsonObject(patient)).build();
+        }
+        return Response.status(404).build();
+    }
+
+    /////////////////////
+    // Transaction
+    /////////////////////
+
+    @Path("/transaction/withBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithBundle() {
+        Bundle result = producerTemplate.requestBody("direct:transactionWithBundle-r4", createTransactionBundle(),
+                Bundle.class);
+        return result.getEntry().get(0).getResponse().getStatus();
+    }
+
+    @Path("/transaction/withStringBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithStringBundle() {
+        Bundle transactionBundle = createTransactionBundle();
+        String stringBundle = fhirContextInstance.get().newJsonParser().encodeResourceToString(transactionBundle);
+        return producerTemplate.requestBody("direct:transactionWithStringBundle-r4", stringBundle, String.class);
+    }
+
+    @Path("/transaction/withResources")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @SuppressWarnings("unchecked")
+    public int transactionWithResources(@QueryParam("summaryEnum") boolean summaryEnum) {
+        Patient oscar = new Patient().addName(new HumanName().addGiven("Oscar").setFamily("Peterson"));
+        Patient bobbyHebb = new Patient().addName(new HumanName().addGiven("Bobby").setFamily("Hebb"));
+        List<IBaseResource> patients = new ArrayList<>(2);
+        patients.add(oscar);
+        patients.add(bobbyHebb);
+
+        Map<String, Object> headers = new HashMap<>();
+        if (summaryEnum) {
+            headers.put(ExtraParameters.SUMMARY_ENUM.getHeaderName(), SummaryEnum.DATA);
+        }
+
+        List<IBaseResource> result = producerTemplate.requestBodyAndHeaders("direct:transactionWithResources-r4", patients,
+                headers, List.class);
+        return result.size();
+    }
+
+    /////////////////////
+    // Update
+    /////////////////////
+
+    @Path("/update/resource")
+    @POST
+    public void updateResource(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-r4", null, headers);
+    }
+
+    @Path("/update/resource/withoutId")
+    @POST
+    public void updateResourceWithoutId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-r4", null, headers);
+    }
+
+    @Path("/update/resource/withStringId")
+    @POST
+    public void updateResourceWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceWithStringId-r4", null, headers);
+    }
+
+    @Path("/update/resource/asString")
+    @POST
+    public void updateResourceAsString(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsString-r4", null, headers);
+    }
+
+    @Path("/update/resource/asStringWithStringId")
+    @POST
+    public void updateResourceAsStringWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsStringWithStringId-r4", null, headers);
+    }
+
+    @Path("/update/resource/bySearchUrl")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceBySearchUrl(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getIdElement().getIdPart(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrl-r4", null, headers,
+                MethodOutcome.class);
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    @Path("/update/resource/bySearchUrlAndResourceAsString")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceByUrlAndResourceAsString(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getId(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrlAndResourceAsString-r4",
+                null, headers, MethodOutcome.class);
+
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    /////////////////////
+    // Validate
+    /////////////////////
+
+    @Path("/validate/resource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResource() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResource-r4", patient, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    @Path("/validate/resourceAsString")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResourceAsString() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        String body = this.fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResourceAsString-r4", body, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    private JsonObject patientToJsonObject(Patient patient) {
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("address", patient.getAddress().get(0).getLine().get(0).asStringValue());
+        builder.add("firstName", patient.getName().get(0).getGiven().get(0).asStringValue());
+        builder.add("lastName", patient.getName().get(0).getFamily());
+
+        Date birthDate = patient.getBirthDate();
+        if (birthDate != null) {
+            String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(birthDate);
+            builder.add("birthDate", formattedDate);
+        }
+        return builder.build();
+    }
+
+    private Bundle createTransactionBundle() {
+        Bundle input = new Bundle();
+        input.setType(Bundle.BundleType.TRANSACTION);
+        input.addEntry()
+                .setResource(new Patient().addName(new HumanName().addGiven("Art").setFamily("Tatum")))
+                .getRequest()
+                .setMethod(Bundle.HTTPVerb.POST);
+        return input;
+    }
+
+    private IGenericClient getFhirClient() {
+        FhirComponent component = context.getComponent("fhir-r4", FhirComponent.class);
+        return FhirHelper.createClient(component.getConfiguration(), context);
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4RouteBuilder.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4RouteBuilder.java
index 11ce9a5..1efc6d1 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4RouteBuilder.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR4RouteBuilder.java
@@ -22,14 +22,10 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.parser.StrictErrorHandler;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.fhir.FhirJsonDataFormat;
-import org.apache.camel.component.fhir.FhirXmlDataFormat;
 import org.apache.camel.quarkus.component.fhir.FhirFlags;
 
 @ApplicationScoped
-public class FhirR4RouteBuilder extends RouteBuilder {
+public class FhirR4RouteBuilder extends AbstractFhirRouteBuilder {
 
     private static final Boolean ENABLED = new FhirFlags.R4Enabled().getAsBoolean();
 
@@ -38,29 +34,17 @@ public class FhirR4RouteBuilder extends RouteBuilder {
     Instance<FhirContext> fhirContextInstance;
 
     @Override
-    public void configure() {
-        if (ENABLED) {
-            FhirContext fhirContext = fhirContextInstance.get();
-            fhirContext.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirJsonDataFormat fhirJsonDataFormat = new FhirJsonDataFormat();
-            fhirJsonDataFormat.setFhirContext(fhirContext);
-            fhirJsonDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirXmlDataFormat fhirXmlDataFormat = new FhirXmlDataFormat();
-            fhirXmlDataFormat.setFhirContext(fhirContext);
-            fhirXmlDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            from("direct:json-to-r4")
-                    .unmarshal(fhirJsonDataFormat)
-                    .marshal(fhirJsonDataFormat);
+    String getFhirVersion() {
+        return "r4";
+    }
 
-            from("direct:xml-to-r4")
-                    .unmarshal(fhirXmlDataFormat)
-                    .marshal(fhirXmlDataFormat);
+    @Override
+    FhirContext getFhirContext() {
+        return fhirContextInstance.get();
+    }
 
-            from("direct:create-r4")
-                    .to("fhir://create/resource?inBody=resourceAsString&fhirContext=#R4");
-        }
+    @Override
+    boolean isEnabled() {
+        return ENABLED;
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Resource.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Resource.java
index d0526e8..ad5280b 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Resource.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Resource.java
@@ -17,19 +17,66 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
+import java.net.URLEncoder;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Instance;
 import javax.inject.Inject;
-import javax.ws.rs.Consumes;
+import javax.inject.Named;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PATCH;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.api.CacheControlDirective;
+import ca.uhn.fhir.rest.api.EncodingEnum;
 import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.api.PreferReturnEnum;
+import ca.uhn.fhir.rest.api.SummaryEnum;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
 import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.fhir.FhirComponent;
+import org.apache.camel.component.fhir.api.ExtraParameters;
+import org.apache.camel.component.fhir.internal.FhirHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.hl7.fhir.instance.model.api.IBaseBundle;
+import org.hl7.fhir.instance.model.api.IBaseMetaType;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r5.model.Bundle;
+import org.hl7.fhir.r5.model.CapabilityStatement;
+import org.hl7.fhir.r5.model.HumanName;
+import org.hl7.fhir.r5.model.IdType;
+import org.hl7.fhir.r5.model.Meta;
+import org.hl7.fhir.r5.model.Narrative;
+import org.hl7.fhir.r5.model.OperationOutcome;
+import org.hl7.fhir.r5.model.Parameters;
+import org.hl7.fhir.r5.model.Patient;
+
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_ADDRESS;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_FIRST_NAME;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_LAST_NAME;
 
 @Path("/r5")
 @ApplicationScoped
@@ -38,41 +85,1115 @@ public class FhirR5Resource {
     @Inject
     ProducerTemplate producerTemplate;
 
-    @Path("/fhir2json")
+    @Inject
+    CamelContext context;
+
+    @Inject
+    @Named("R5")
+    Instance<FhirContext> fhirContextInstance;
+
+    /////////////////////
+    // Capabilities
+    /////////////////////
+
+    @Path("/capabilities")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String capabilities(@QueryParam("encodeAs") String encodeAs) {
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAs.equals("encodeJson") || encodeAs.equals("encodeXml")) {
+            headers.put(encodeAs, Boolean.TRUE);
+        }
+
+        CapabilityStatement result = producerTemplate.requestBodyAndHeaders("direct:capabilities-r5", CapabilityStatement.class,
+                headers, CapabilityStatement.class);
+        return result.getStatus().name();
+    }
+
+    /////////////////////
+    // Create
+    /////////////////////
+
+    @Path("/createPatientAsStringResource")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatientAsStringResource(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address,
+            @QueryParam("encodeAs") String encodeAs) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = null;
+        Map<String, Object> headers = new HashMap<>();
+        headers.put(encodeAs, Boolean.TRUE);
+
+        if (encodeAs.equals("encodeJson")) {
+            patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+        } else {
+            patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:createResourceAsString-r5", patientString,
+                headers,
+                MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    @Path("/createPatient")
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    public JsonObject createPatient(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        MethodOutcome result = producerTemplate.requestBody("direct:createResource-r5", patient, MethodOutcome.class);
+
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("created", result.getCreated());
+        builder.add("id", result.getId().getValue());
+        builder.add("idPart", result.getId().getIdPart());
+        builder.add("idUnqualifiedVersionless", result.getId().toUnqualifiedVersionless().getValue());
+        builder.add("version", result.getId().getVersionIdPart());
+        return builder.build();
+    }
+
+    /////////////////////
+    // Dataformats
+    /////////////////////
+
+    @Path("/fhir2json")
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2json(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:json-to-r5", patient, InputStream.class)) {
+    public Response fhir2json(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newJsonParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:json-to-r5", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
     @Path("/fhir2xml")
-    @POST
-    @Consumes(MediaType.APPLICATION_XML)
+    @GET
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    public Response fhir2xml(String patient) throws Exception {
-        try (InputStream response = producerTemplate.requestBody("direct:xml-to-r5", patient, InputStream.class)) {
+    public Response fhir2xml(
+            @QueryParam("firstName") String firstName,
+            @QueryParam("lastName") String lastName,
+            @QueryParam("address") String address) throws Exception {
+
+        Patient patient = new Patient();
+        patient.addAddress().addLine(address);
+        patient.addName().addGiven(firstName).setFamily(lastName);
+
+        String patientString = fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+
+        try (InputStream response = producerTemplate.requestBody("direct:xml-to-r5", patientString, InputStream.class)) {
             return Response
-                    .created(new URI("https://camel.apache.org/"))
+                    .created(new URI("https:camel.apache.org/"))
                     .entity(response)
                     .build();
         }
     }
 
-    @Path("/createPatient")
+    /////////////////////
+    // Delete
+    /////////////////////
+
+    @Path("/deletePatient/byModel")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByModel(@QueryParam("id") String id) {
+        Patient patient = new Patient();
+        patient.addAddress().addLine(PATIENT_ADDRESS);
+        patient.addName().addGiven(PATIENT_FIRST_NAME).setFamily(PATIENT_LAST_NAME);
+        patient.setId(id);
+
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:delete-r5", patient, IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byId")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientById(@QueryParam("id") String id) {
+        IBaseOperationOutcome result = producerTemplate.requestBody("direct:deleteById-r5", new IdType(id),
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byIdPart")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByIdPart(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.type", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteByStringId-r5", null, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    @Path("/deletePatient/byUrl")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public String deletePatientByUrl(@QueryParam("cache") boolean noCache) {
+        Map<String, Object> headers = new HashMap<>();
+        if (noCache) {
+            headers.put(ExtraParameters.CACHE_CONTROL_DIRECTIVE.getHeaderName(), new CacheControlDirective().setNoCache(true));
+        }
+
+        String body = String.format("Patient?given=%s&family=%s", PATIENT_FIRST_NAME, PATIENT_LAST_NAME);
+        IBaseOperationOutcome result = producerTemplate.requestBodyAndHeaders("direct:deleteConditionalByUrl-r5", body, headers,
+                IBaseOperationOutcome.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // History
+    /////////////////////
+
+    @Path("/history/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnInstance(@QueryParam("id") String id) {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", new IdType(id));
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnInstance-r5", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnServer-r5", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/history/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int historyOnType() {
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.returnType", Bundle.class);
+        headers.put("CamelFhir.count", 1);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:historyOnType-r5", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Load page
+    /////////////////////
+
+    @Path("/load/page/byUrl")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageByUrl() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.url", nextPageLink);
+        headers.put("CamelFhir.returnType", Bundle.class);
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPageByUrl-r5", null, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/next")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPageNext() {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        Bundle result = producerTemplate.requestBody("direct:loadPageNext-r5", bundle, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    @Path("/load/page/previous")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int loadPagePrevious(@QueryParam("encodeAsXml") boolean encodeAsXml) {
+        String url = "Patient?_count=2";
+        Bundle bundle = getFhirClient()
+                .search()
+                .byUrl(url)
+                .returnBundle(Bundle.class)
+                .execute();
+
+        String nextPageLink = bundle.getLink("next").getUrl();
+        bundle = getFhirClient()
+                .loadPage()
+                .byUrl(nextPageLink)
+                .andReturnBundle(Bundle.class)
+                .execute();
+
+        Map<String, Object> headers = new HashMap<>();
+        if (encodeAsXml) {
+            headers.put(ExtraParameters.ENCODING_ENUM.getHeaderName(), EncodingEnum.XML);
+        }
+
+        Bundle result = producerTemplate.requestBodyAndHeaders("direct:loadPagePrevious-r5", bundle, headers, Bundle.class);
+        return result.getEntry().size();
+    }
+
+    /////////////////////
+    // Meta
+    /////////////////////
+
+    @Path("/meta")
     @POST
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.TEXT_PLAIN)
-    public Response createPatient(String patient) throws Exception {
-        MethodOutcome result = producerTemplate.requestBody("direct:create-r5", patient, MethodOutcome.class);
-        return Response
-                .created(new URI("https://camel.apache.org/"))
-                .entity(result.getId().getIdPart())
-                .build();
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaAdd(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaAdd-r5", null, headers, IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta")
+    @DELETE
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaDelete(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+        Meta inMeta = new Meta();
+        inMeta.addTag().setSystem("urn:system1").setCode("urn:code1");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.meta", inMeta);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaDelete-r5", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromResource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromResource(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        final Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.id", iIdType);
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromResource-r5", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromServer() {
+        IBaseMetaType result = producerTemplate.requestBody("direct:metaGetFromServer-r5", Meta.class, IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    @Path("/meta/getFromType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public int metaGetFromType(@QueryParam("preferResponseType") boolean preferResponseType) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.metaType", Meta.class);
+        headers.put("CamelFhir.resourceType", "Patient");
+
+        if (preferResponseType) {
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPE.getHeaderName(), Patient.class);
+        }
+
+        IBaseMetaType result = producerTemplate.requestBodyAndHeaders("direct:metaGetFromType-r5", null, headers,
+                IBaseMetaType.class);
+        return result.getTag().size();
+    }
+
+    /////////////////////
+    // Operation
+    /////////////////////
+
+    @Path("/operation/onInstance")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstance(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstance-r5", null, headers,
+                Parameters.class);
+
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onInstanceVersion")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnInstanceVersion(@QueryParam("id") String id) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnInstanceVersion-r5", null, headers,
+                Parameters.class);
+
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/onServer")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public boolean operationOnServer() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.name", "$get-resource-counts");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.TRUE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnServer-r5", null, headers,
+                Parameters.class);
+        return result != null;
+    }
+
+    @Path("/operation/onType")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationOnType() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceType", Patient.class);
+        headers.put("CamelFhir.name", "everything");
+        headers.put("CamelFhir.parameters", null);
+        headers.put("CamelFhir.outputParameterType", Parameters.class);
+        headers.put("CamelFhir.useHttpGet", Boolean.FALSE);
+        headers.put("CamelFhir.returnType", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        Parameters result = producerTemplate.requestBodyAndHeaders("direct:operationOnType-r5", null, headers,
+                Parameters.class);
+        Parameters.ParametersParameterComponent parametersParameterComponent = result.getParameter().get(0);
+        Bundle bundle = (Bundle) parametersParameterComponent.getResource();
+        Bundle.BundleEntryComponent bundleEntryComponent = bundle.getEntry().get(0);
+        return bundleEntryComponent.getResource().getIdElement().toUnqualifiedVersionless().getValue();
+    }
+
+    @Path("/operation/processMessage")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String operationProcessMessage() {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.respondToUri", null);
+        headers.put("CamelFhir.msgBundle", null);
+        headers.put("CamelFhir.asynchronous", Boolean.FALSE);
+        headers.put("CamelFhir.responseClass", null);
+        headers.put("CamelFhir.extraParameters", null);
+
+        IBaseBundle result = producerTemplate.requestBodyAndHeaders("direct:operationProcessMessage-r5", null, headers,
+                IBaseBundle.class);
+        return result.getIdElement().getIdPart();
+    }
+
+    /////////////////////
+    // Patch
+    /////////////////////
+
+    @Path("/patch/byId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchById(@QueryParam("id") String id, String patch) {
+        IdType iIdType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.id", iIdType);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchById-r5", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byStringId")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByStringId(
+            @QueryParam("id") String id,
+            @QueryParam("preferResponseTypes") boolean preferResponseTypes,
+            String patch) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        if (preferResponseTypes) {
+            List<Class<? extends IBaseResource>> preferredResponseTypes = new ArrayList<>();
+            preferredResponseTypes.add(Patient.class);
+            headers.put(ExtraParameters.PREFER_RESPONSE_TYPES.getHeaderName(), preferredResponseTypes);
+        }
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchBySid-r5", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    @Path("/patch/byUrl")
+    @PATCH
+    @Produces(MediaType.TEXT_PLAIN)
+    public String patchByUrl(@QueryParam("id") String id, String patch) throws UnsupportedEncodingException {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.patchBody", patch);
+        headers.put("CamelFhir.url", "Patient?" + Patient.SP_RES_ID + "=" + id);
+        headers.put("CamelFhir.preferReturn", null);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:patchByUrl-r5", null, headers,
+                MethodOutcome.class);
+
+        return getFhirClient()
+                .read()
+                .resource(Patient.class)
+                .withId(result.getId())
+                .preferResponseType(Patient.class)
+                .execute()
+                .getGender()
+                .getDisplay();
+    }
+
+    /////////////////////
+    // Read
+    /////////////////////
+
+    @Path("/readPatient/byId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientById(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.id", new IdType(id));
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readById-r5", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongId-r5", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringId")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringId(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringId-r5", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIdAndStringResource(@QueryParam("id") String id) {
+        IdType idType = new IdType(id);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.id", idType);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIdAndStringResource-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byLongIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByLongIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.longId", Long.valueOf(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByLongIdAndStringResource-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndStringResource-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersion")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersion(@QueryParam("id") String id, @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersion-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringIdAndVersionWithResourceClass")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringIdAndVersionWithResourceClass(@QueryParam("id") String id,
+            @QueryParam("version") String version) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.stringId", id);
+        headers.put("CamelFhir.version", version);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringIdAndVersionAndStringResource-r5", null,
+                    headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byIUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByIUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByIUrl-r5", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByUrl(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", Patient.class);
+        headers.put("CamelFhir.url", id);
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrl-r5", null, headers, Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byStringUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readPatientByStringUrlAndStringResource(@QueryParam("id") String id) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.iUrl", new IdType(id));
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByStringUrlAndStringResource-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    @Path("/readPatient/byUrlAndStringResource")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response readByUrlAndStringResource(@QueryParam("id") String id, @QueryParam("prettyPrint") boolean prettyPrint) {
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceClass", "Patient");
+        headers.put("CamelFhir.url", id);
+
+        if (prettyPrint) {
+            headers.put(ExtraParameters.PRETTY_PRINT.getHeaderName(), Boolean.TRUE);
+        }
+
+        try {
+            Patient result = producerTemplate.requestBodyAndHeaders("direct:readByUrlAndStringResource-r5", null, headers,
+                    Patient.class);
+            return Response.ok().entity(patientToJsonObject(result)).build();
+        } catch (CamelExecutionException e) {
+            Throwable cause = e.getExchange().getException().getCause();
+            if (cause instanceof ResourceGoneException) {
+                return Response.status(404).build();
+            }
+        }
+
+        return Response.noContent().build();
+    }
+
+    /////////////////////
+    // Search
+    /////////////////////
+
+    @Path("/search/byUrl")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response searchByUrl(@QueryParam("id") String id) {
+        String url = "Patient?" + Patient.SP_RES_ID + "=" + id + "&_format=json";
+        Bundle result = producerTemplate.requestBody("direct:searchByUrl-r5", url, Bundle.class);
+
+        List<Bundle.BundleEntryComponent> entry = result.getEntry();
+        if (ObjectHelper.isNotEmpty(entry)) {
+            Patient patient = (Patient) entry.get(0).getResource();
+            return Response.ok().entity(patientToJsonObject(patient)).build();
+        }
+        return Response.status(404).build();
+    }
+
+    /////////////////////
+    // Transaction
+    /////////////////////
+
+    @Path("/transaction/withBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithBundle() {
+        Bundle result = producerTemplate.requestBody("direct:transactionWithBundle-r5", createTransactionBundle(),
+                Bundle.class);
+        return result.getEntry().get(0).getResponse().getStatus();
+    }
+
+    @Path("/transaction/withStringBundle")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String transactionWithStringBundle() {
+        Bundle transactionBundle = createTransactionBundle();
+        String stringBundle = fhirContextInstance.get().newJsonParser().encodeResourceToString(transactionBundle);
+        return producerTemplate.requestBody("direct:transactionWithStringBundle-r5", stringBundle, String.class);
+    }
+
+    @Path("/transaction/withResources")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @SuppressWarnings("unchecked")
+    public int transactionWithResources(@QueryParam("summaryEnum") boolean summaryEnum) {
+        Patient oscar = new Patient().addName(new HumanName().addGiven("Oscar").setFamily("Peterson"));
+        Patient bobbyHebb = new Patient().addName(new HumanName().addGiven("Bobby").setFamily("Hebb"));
+        List<IBaseResource> patients = new ArrayList<>(2);
+        patients.add(oscar);
+        patients.add(bobbyHebb);
+
+        Map<String, Object> headers = new HashMap<>();
+        if (summaryEnum) {
+            headers.put(ExtraParameters.SUMMARY_ENUM.getHeaderName(), SummaryEnum.DATA);
+        }
+
+        List<IBaseResource> result = producerTemplate.requestBodyAndHeaders("direct:transactionWithResources-r5", patients,
+                headers, List.class);
+        return result.size();
+    }
+
+    /////////////////////
+    // Update
+    /////////////////////
+
+    @Path("/update/resource")
+    @POST
+    public void updateResource(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-r5", null, headers);
+    }
+
+    @Path("/update/resource/withoutId")
+    @POST
+    public void updateResourceWithoutId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResource-r5", null, headers);
+    }
+
+    @Path("/update/resource/withStringId")
+    @POST
+    public void updateResourceWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceWithStringId-r5", null, headers);
+    }
+
+    @Path("/update/resource/asString")
+    @POST
+    public void updateResourceAsString(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.id", patient.getIdElement());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsString-r5", null, headers);
+    }
+
+    @Path("/update/resource/asStringWithStringId")
+    @POST
+    public void updateResourceAsStringWithStringId(@QueryParam("id") String id) throws ParseException {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.stringId", patient.getIdElement().getIdPart());
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        producerTemplate.sendBodyAndHeaders("direct:updateResourceAsStringWithStringId-r5", null, headers);
+    }
+
+    @Path("/update/resource/bySearchUrl")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceBySearchUrl(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getIdElement().getIdPart(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resource", patient);
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrl-r5", null, headers,
+                MethodOutcome.class);
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    @Path("/update/resource/bySearchUrlAndResourceAsString")
+    @POST
+    @Produces(MediaType.TEXT_PLAIN)
+    public String updateResourceByUrlAndResourceAsString(@QueryParam("id") String id) throws Exception {
+        Patient patient = getFhirClient().read()
+                .resource(Patient.class)
+                .withId(id)
+                .preferResponseType(Patient.class)
+                .execute();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+        Date date = dateFormat.parse("1998-04-29");
+        patient.setBirthDate(date);
+
+        String url = "Patient?" + Patient.SP_IDENTIFIER + '=' + URLEncoder.encode(patient.getId(), "UTF-8");
+
+        Map<String, Object> headers = new HashMap<>();
+        headers.put("CamelFhir.resourceAsString", fhirContextInstance.get().newJsonParser().encodeResourceToString(patient));
+        headers.put("CamelFhir.url", url);
+        headers.put("CamelFhir.preferReturn", PreferReturnEnum.REPRESENTATION);
+
+        MethodOutcome result = producerTemplate.requestBodyAndHeaders("direct:updateResourceBySearchUrlAndResourceAsString-r5",
+                null, headers, MethodOutcome.class);
+
+        Patient updated = (Patient) result.getResource();
+        return dateFormat.format(updated.getBirthDate());
+    }
+
+    /////////////////////
+    // Validate
+    /////////////////////
+
+    @Path("/validate/resource")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResource() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResource-r5", patient, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    @Path("/validate/resourceAsString")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String validateResourceAsString() {
+        Patient patient = new Patient()
+                .addName(new HumanName()
+                        .addGiven(PATIENT_FIRST_NAME)
+                        .setFamily(PATIENT_LAST_NAME));
+
+        patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
+        patient.getText().setDivAsString("<div>This is the narrative text</div>");
+
+        String body = this.fhirContextInstance.get().newXmlParser().encodeResourceToString(patient);
+        MethodOutcome result = producerTemplate.requestBody("direct:validateResourceAsString-r5", body, MethodOutcome.class);
+
+        OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
+        return operationOutcome.getIssue().get(0).getDiagnostics();
+    }
+
+    private JsonObject patientToJsonObject(Patient patient) {
+        JsonObjectBuilder builder = Json.createObjectBuilder();
+        builder.add("address", patient.getAddress().get(0).getLine().get(0).asStringValue());
+        builder.add("firstName", patient.getName().get(0).getGiven().get(0).asStringValue());
+        builder.add("lastName", patient.getName().get(0).getFamily());
+
+        Date birthDate = patient.getBirthDate();
+        if (birthDate != null) {
+            String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(birthDate);
+            builder.add("birthDate", formattedDate);
+        }
+        return builder.build();
+    }
+
+    private Bundle createTransactionBundle() {
+        Bundle input = new Bundle();
+        input.setType(Bundle.BundleType.TRANSACTION);
+        input.addEntry()
+                .setResource(new Patient().addName(new HumanName().addGiven("Art").setFamily("Tatum")))
+                .getRequest()
+                .setMethod(Bundle.HTTPVerb.POST);
+        return input;
+    }
+
+    private IGenericClient getFhirClient() {
+        FhirComponent component = context.getComponent("fhir-r5", FhirComponent.class);
+        return FhirHelper.createClient(component.getConfiguration(), context);
     }
 }
diff --git a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5RouteBuilder.java b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5RouteBuilder.java
index 4869330..ed81402 100644
--- a/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5RouteBuilder.java
+++ b/integration-tests/fhir/src/main/java/org/apache/camel/quarkus/component/fhir/it/FhirR5RouteBuilder.java
@@ -22,14 +22,10 @@ import javax.inject.Inject;
 import javax.inject.Named;
 
 import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.parser.StrictErrorHandler;
-import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.component.fhir.FhirJsonDataFormat;
-import org.apache.camel.component.fhir.FhirXmlDataFormat;
 import org.apache.camel.quarkus.component.fhir.FhirFlags;
 
 @ApplicationScoped
-public class FhirR5RouteBuilder extends RouteBuilder {
+public class FhirR5RouteBuilder extends AbstractFhirRouteBuilder {
 
     private static final Boolean ENABLED = new FhirFlags.R5Enabled().getAsBoolean();
 
@@ -38,29 +34,17 @@ public class FhirR5RouteBuilder extends RouteBuilder {
     Instance<FhirContext> fhirContextInstance;
 
     @Override
-    public void configure() {
-        if (ENABLED) {
-            FhirContext fhirContext = fhirContextInstance.get();
-            fhirContext.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirJsonDataFormat fhirJsonDataFormat = new FhirJsonDataFormat();
-            fhirJsonDataFormat.setFhirContext(fhirContext);
-            fhirJsonDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            FhirXmlDataFormat fhirXmlDataFormat = new FhirXmlDataFormat();
-            fhirXmlDataFormat.setFhirContext(fhirContext);
-            fhirXmlDataFormat.setParserErrorHandler(new StrictErrorHandler());
-
-            from("direct:json-to-r5")
-                    .unmarshal(fhirJsonDataFormat)
-                    .marshal(fhirJsonDataFormat);
+    String getFhirVersion() {
+        return "r5";
+    }
 
-            from("direct:xml-to-r5")
-                    .unmarshal(fhirXmlDataFormat)
-                    .marshal(fhirXmlDataFormat);
+    @Override
+    FhirContext getFhirContext() {
+        return fhirContextInstance.get();
+    }
 
-            from("direct:create-r5")
-                    .to("fhir://create/resource?inBody=resourceAsString&fhirContext=#R5");
-        }
+    @Override
+    boolean isEnabled() {
+        return ENABLED;
     }
 }
diff --git a/integration-tests/fhir/src/main/resources/application.properties b/integration-tests/fhir/src/main/resources/application.properties
index b7e9f8f..af49acc 100644
--- a/integration-tests/fhir/src/main/resources/application.properties
+++ b/integration-tests/fhir/src/main/resources/application.properties
@@ -19,17 +19,10 @@
 # Quarkus :: Camel :: FHIR
 #
 # The HAPI-FHIR library, on which camel-fhir depends on, heavily uses reflection which affects performance in Quarkus
-# (memory footprint, build time, CPU resources etc...). For the sake of time, only R4 (which is the default FHIR
-# version supported by the test server)
+# (memory footprint, build time, CPU resources etc...). For the sake of time, only R5 is tested by default. To test
+# additional FHIR versions, set the following configuration properties to true.
 #
 quarkus.camel.fhir.enable-dstu2=false
-quarkus.camel.fhir.enable-dstu3=true
+quarkus.camel.fhir.enable-dstu3=false
 quarkus.camel.fhir.enable-r4=false
-quarkus.camel.fhir.enable-r5=false
-
-#
-# Camel :: FHIR
-#
-camel.component.fhir.log = false
-camel.component.fhir.server-url = {{camel.fhir.test-url}}
-camel.component.fhir.fhir-context = #bean:DSTU3
+quarkus.camel.fhir.enable-r5=true
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirTest.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirTest.java
new file mode 100644
index 0000000..1678e65
--- /dev/null
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/AbstractFhirTest.java
@@ -0,0 +1,883 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.fhir.it;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import io.restassured.path.json.JsonPath;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_ADDRESS;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_FIRST_NAME;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_GENDER_PATCH;
+import static org.apache.camel.quarkus.component.fhir.it.FhirConstants.PATIENT_LAST_NAME;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalToIgnoringCase;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+abstract class AbstractFhirTest {
+
+    @ParameterizedTest
+    @ValueSource(strings = { "fhir2json", "fhir2xml" })
+    public void marshalUnmarshal(String path) {
+        RestAssured.given()
+                .get("/" + path)
+                .then()
+                .statusCode(201);
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "encodeJson", "encodeXml" })
+    public void capabilities(String encodeAs) {
+        RestAssured.given()
+                .queryParam("encodeAs", encodeAs)
+                .get("/capabilities")
+                .then()
+                .statusCode(200)
+                .body(is("ACTIVE"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "encodeJson", "encodeXml" })
+    public void createAsStringResource(String encodeAs) {
+        JsonPath result = RestAssured.given()
+                .queryParam("encodeAs", encodeAs)
+                .queryParam("firstName", PATIENT_FIRST_NAME)
+                .queryParam("lastName", PATIENT_LAST_NAME)
+                .queryParam("address", PATIENT_ADDRESS)
+                .contentType(ContentType.TEXT)
+                .post("/createPatientAsStringResource")
+                .then()
+                .statusCode(200)
+                .extract()
+                .jsonPath();
+        try {
+            assertEquals(true, result.getBoolean("created"));
+            assertNotNull(result.getString("id"));
+            assertNotNull(result.getString("idPart"));
+            assertNotNull(result.getString("idUnqualifiedVersionless"));
+            assertNotNull(result.getString("version"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void createAsResource() {
+        JsonPath result = createPatient();
+        try {
+            assertEquals(true, result.getBoolean("created"));
+            assertNotNull(result.getString("id"));
+            assertNotNull(result.getString("idPart"));
+            assertNotNull(result.getString("idUnqualifiedVersionless"));
+            assertNotNull(result.getString("version"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void deleteByModel() {
+        JsonPath result = createPatient();
+
+        String deleteEventId = RestAssured.given()
+                .queryParam("id", result.getString("id"))
+                .delete("/deletePatient/byModel")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        RestAssured.given()
+                .queryParam("id", deleteEventId)
+                .get("/readPatient/byId")
+                .then()
+                .statusCode(404);
+    }
+
+    @Test
+    public void deleteById() {
+        JsonPath result = createPatient();
+
+        String deleteEventId = RestAssured.given()
+                .queryParam("id", result.getString("id"))
+                .delete("/deletePatient/byId")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        RestAssured.given()
+                .queryParam("id", deleteEventId)
+                .get("/readPatient/byId")
+                .then()
+                .statusCode(404);
+    }
+
+    @Test
+    public void deleteByIdPart() {
+        JsonPath result = createPatient();
+
+        String deleteEventId = RestAssured.given()
+                .queryParam("id", result.getString("idPart"))
+                .delete("/deletePatient/byIdPart")
+                .then()
+                .statusCode(200)
+                .extract()
+                .body()
+                .asString();
+
+        RestAssured.given()
+                .queryParam("id", deleteEventId)
+                .get("/readPatient/byId")
+                .then()
+                .statusCode(404);
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    public void deleteByUrl(boolean noCache) {
+        createPatient();
+
+        RestAssured.given()
+                .queryParam("noCache", noCache)
+                .delete("/deletePatient/byUrl")
+                .then()
+                .statusCode(204);
+
+        RestAssured.given()
+                .get("/search/byUrl")
+                .then()
+                .statusCode(404);
+    }
+
+    @Test
+    public void historyOnInstance() {
+        JsonPath result = createPatient();
+
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/history/onInstance")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void historyOnServer() {
+        JsonPath result = createPatient();
+
+        try {
+            RestAssured.given()
+                    .get("/history/onServer")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void historyOnType() {
+        JsonPath result = createPatient();
+
+        try {
+            RestAssured.given()
+                    .get("/history/onType")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void loadPageByUrl() {
+        Set<String> ids = Stream.of(
+                createPatient("First Name 1", "Last Name 1", "Address 1"),
+                createPatient("First Name 2", "Last Name 2", "Address 2"),
+                createPatient("First Name 3", "Last Name 3", "Address 3"))
+                .map(json -> json.getString("id"))
+                .collect(Collectors.toSet());
+
+        try {
+            RestAssured.given()
+                    .get("/load/page/byUrl")
+                    .then()
+                    .statusCode(200)
+                    .body(is("2"));
+        } finally {
+            ids.forEach(this::deletePatient);
+        }
+    }
+
+    @Test
+    public void loadPageByNext() {
+        Set<String> ids = Stream.of(
+                createPatient("First Name 1", "Last Name 1", "Address 1"),
+                createPatient("First Name 2", "Last Name 2", "Address 2"),
+                createPatient("First Name 3", "Last Name 3", "Address 3"))
+                .map(json -> json.getString("id"))
+                .collect(Collectors.toSet());
+
+        try {
+            RestAssured.given()
+                    .get("/load/page/next")
+                    .then()
+                    .statusCode(200)
+                    .body(is("2"));
+        } finally {
+            ids.forEach(this::deletePatient);
+        }
+    }
+
+    @Test
+    public void loadPageByPrevious() {
+        Set<String> ids = Stream.of(
+                createPatient("First Name 1", "Last Name 1", "Address 1"),
+                createPatient("First Name 2", "Last Name 2", "Address 2"),
+                createPatient("First Name 3", "Last Name 3", "Address 3"))
+                .map(json -> json.getString("id"))
+                .collect(Collectors.toSet());
+
+        try {
+            RestAssured.given()
+                    .queryParam("encodeAsXml", false)
+                    .get("/load/page/previous")
+                    .then()
+                    .statusCode(200)
+                    .body(is("2"));
+        } finally {
+            ids.forEach(this::deletePatient);
+        }
+    }
+
+    @Test
+    public void loadPageByPreviousWithEncoding() {
+        Set<String> ids = Stream.of(
+                createPatient("First Name 1", "Last Name 1", "Address 1"),
+                createPatient("First Name 2", "Last Name 2", "Address 2"),
+                createPatient("First Name 3", "Last Name 3", "Address 3"))
+                .map(json -> json.getString("id"))
+                .collect(Collectors.toSet());
+
+        try {
+            RestAssured.given()
+                    .queryParam("encodeAsXml", false)
+                    .get("/load/page/previous")
+                    .then()
+                    .statusCode(200)
+                    .body(is("2"));
+        } finally {
+            ids.forEach(this::deletePatient);
+        }
+    }
+
+    @Test
+    public void metaAdd() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/meta")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void metaDelete() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/meta")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .delete("/meta")
+                    .then()
+                    .statusCode(200)
+                    .body(is("0"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void metaGetFromResource() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/meta")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/meta/getFromResource")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void metaGetFromServer() {
+        RestAssured.given()
+                .get("/meta/getFromServer")
+                .then()
+                .statusCode(200)
+                .body(greaterThanOrEqualTo("2"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    public void metaGetFromType(boolean preferResponseType) {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/meta")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+
+            RestAssured.given()
+                    .queryParam("preferResponseType", preferResponseType)
+                    .get("/meta/getFromType")
+                    .then()
+                    .statusCode(200)
+                    .body(is("1"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void operationOnInstance() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/operation/onInstance")
+                    .then()
+                    .statusCode(200)
+                    .body(is(result.getString("idUnqualifiedVersionless")));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void operationOnInstanceVersion() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/operation/onInstanceVersion")
+                    .then()
+                    .statusCode(200)
+                    .body(is(result.getString("idUnqualifiedVersionless")));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void operationOnServer() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .get("/operation/onServer")
+                    .then()
+                    .statusCode(200)
+                    .body(is("true"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void operationOnType() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .get("/operation/onType")
+                    .then()
+                    .statusCode(200)
+                    .body(is(result.getString("idUnqualifiedVersionless")));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Disabled("ProcessMessage is not implemented on the mock FHIR server")
+    @Test
+    public void operationProcessMessage() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .get("/operation/processMessage")
+                    .then()
+                    .statusCode(200)
+                    .body(is(result.getString("id")));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void patchById() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .body(PATIENT_GENDER_PATCH)
+                    .patch("/patch/byId")
+                    .then()
+                    .statusCode(200)
+                    .body(equalToIgnoringCase("Female"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    public void patchByStringId(boolean preferResponseTypes) {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .queryParam("preferResponseTypes", preferResponseTypes)
+                    .body(PATIENT_GENDER_PATCH)
+                    .patch("/patch/byStringId")
+                    .then()
+                    .statusCode(200)
+                    .body(equalToIgnoringCase("female"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void patchByUrl() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .body(PATIENT_GENDER_PATCH)
+                    .patch("/patch/byUrl")
+                    .then()
+                    .statusCode(200)
+                    .body(equalToIgnoringCase("Female"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readById() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byId")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByLongId() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/readPatient/byLongId")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByStringId() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/readPatient/byStringId")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByIdAndStringResource() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byIdAndStringResource")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByLongIdAndStringResource() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/readPatient/byLongIdAndStringResource")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByStringIdAndStringResource() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/readPatient/byStringIdAndStringResource")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByStringIdAndVersion() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .queryParam("version", result.getString("version"))
+                    .get("/readPatient/byStringIdAndVersion")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByStringIdAndVersionWithResourceClass() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .queryParam("version", result.getString("version"))
+                    .get("/readPatient/byStringIdAndVersionWithResourceClass")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByIUrl() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byIUrl")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByUrl() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byUrl")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void readByStringUrlAndStringResource() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byStringUrlAndStringResource")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    public void readByUrlAndStringResource(boolean prettyPrint) {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("prettyPrint", prettyPrint)
+                    .queryParam("id", result.getString("id"))
+                    .get("/readPatient/byUrlAndStringResource")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void searchByUrl() {
+        JsonPath result = createPatient();
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/search/byUrl")
+                    .then()
+                    .statusCode(200)
+                    .body(
+                            "address", is(PATIENT_ADDRESS),
+                            "firstName", is(PATIENT_FIRST_NAME),
+                            "lastName", is(PATIENT_LAST_NAME));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void transactionWithBundle() {
+        RestAssured.given()
+                .get("/transaction/withBundle")
+                .then()
+                .statusCode(200)
+                .body(containsString("Created"));
+    }
+
+    @Test
+    public void transactionWithStringBundle() {
+        RestAssured.given()
+                .get("/transaction/withStringBundle")
+                .then()
+                .statusCode(200)
+                .body(containsString("Created"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(booleans = { false, true })
+    public void transactionWithResources(boolean summaryEnum) {
+        RestAssured.given()
+                .queryParam("summaryEnum", summaryEnum)
+                .get("/transaction/withResources")
+                .then()
+                .statusCode(200)
+                .body(is("2"));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "resource",
+            "resource/withoutId",
+            "resource/withStringId",
+            "resource/asString",
+            "resource/asStringWithStringId",
+    })
+    public void updateResource(String updateApiPath) {
+        JsonPath result = createPatient();
+        assertNull(result.get("birthDate"));
+
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/update/" + updateApiPath)
+                    .then()
+                    .statusCode(204);
+
+            RestAssured.given()
+                    .queryParam("id", result.getString("idPart"))
+                    .get("/readPatient/byId")
+                    .then()
+                    .statusCode(200)
+                    .body("birthDate", is("1998-04-29"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = {
+            "resource/bySearchUrl",
+            "resource/bySearchUrlAndResourceAsString"
+    })
+    public void updateResourceByUrl(String updateApiPath) {
+        JsonPath result = createPatient();
+        assertNull(result.get("birthDate"));
+
+        try {
+            RestAssured.given()
+                    .queryParam("id", result.getString("id"))
+                    .post("/update/" + updateApiPath)
+                    .then()
+                    .statusCode(200)
+                    .body(is("1998-04-29"));
+        } finally {
+            deletePatient(result.getString("id"));
+        }
+    }
+
+    @Test
+    public void validateResource() {
+        RestAssured.given()
+                .get("/validate/resource")
+                .then()
+                .statusCode(200)
+                .body(is("No issues detected during validation"));
+    }
+
+    @Test
+    public void validateResourceAsString() {
+        RestAssured.given()
+                .get("/validate/resourceAsString")
+                .then()
+                .statusCode(200)
+                .body(is("No issues detected during validation"));
+    }
+
+    private JsonPath createPatient() {
+        return createPatient(PATIENT_FIRST_NAME, PATIENT_LAST_NAME, PATIENT_ADDRESS);
+    }
+
+    private JsonPath createPatient(String firstName, String lastName, String address) {
+        return RestAssured.given()
+                .queryParam("firstName", firstName)
+                .queryParam("lastName", lastName)
+                .queryParam("address", address)
+                .contentType(ContentType.TEXT)
+                .post("/createPatient")
+                .then()
+                .statusCode(200)
+                .extract()
+                .jsonPath();
+    }
+
+    private void deletePatient(String id) {
+        RestAssured.given()
+                .queryParam("id", id)
+                .delete("/deletePatient/byId")
+                .then()
+                .statusCode(200);
+    }
+}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientTest.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientTest.java
deleted file mode 100644
index b5967a3..0000000
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientTest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.quarkus.component.fhir.it;
-
-import ca.uhn.fhir.context.FhirContext;
-import io.quarkus.test.common.QuarkusTestResource;
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import io.restassured.http.ContentType;
-import org.apache.camel.quarkus.component.fhir.FhirFlags;
-import org.apache.camel.quarkus.test.EnabledIf;
-import org.jboss.logging.Logger;
-import org.junit.jupiter.api.Test;
-
-@QuarkusTest
-@QuarkusTestResource(FhirTestResource.class)
-class FhirClientTest {
-    private static final Logger LOG = Logger.getLogger(FhirClientTest.class);
-
-    @Test
-    @EnabledIf(FhirFlags.R5Enabled.class)
-    public void fhirClientR5() {
-        LOG.info("Running R5 Client test");
-
-        final org.hl7.fhir.r5.model.Patient patient = getR5Patient();
-        final String patientString = FhirContext.forR5().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString.getBytes()).post("/r5/createPatient")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.R4Enabled.class)
-    public void fhirClientR4() {
-        LOG.info("Running R4 Client test");
-
-        final org.hl7.fhir.r4.model.Patient patient = getR4Patient();
-        final String patientString = FhirContext.forR4().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString.getBytes()).post("/r4/createPatient")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu3Enabled.class)
-    public void fhirClientDstu3() {
-        LOG.info("Running DSTU3 Client test");
-
-        final org.hl7.fhir.dstu3.model.Patient patient = getDstu3Patient();
-        final String patientString = FhirContext.forDstu3().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/dstu3/createPatient")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu2Enabled.class)
-    public void fhirClientDstu2() {
-        LOG.info("Running DSTU2 CLIENT test");
-
-        final ca.uhn.fhir.model.dstu2.resource.Patient patient = getDstu2Patient();
-        final String patientString = FhirContext.forDstu2().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/dstu2/createPatient")
-                .then().statusCode(201);
-    }
-
-    private ca.uhn.fhir.model.dstu2.resource.Patient getDstu2Patient() {
-        ca.uhn.fhir.model.dstu2.resource.Patient patient = new ca.uhn.fhir.model.dstu2.resource.Patient();
-        patient.addName().addGiven("Sherlock").addFamily("Holmes");
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        return patient;
-    }
-
-    private org.hl7.fhir.dstu3.model.Patient getDstu3Patient() {
-        org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        return patient;
-    }
-
-    private org.hl7.fhir.r4.model.Patient getR4Patient() {
-        org.hl7.fhir.r4.model.Patient patient = new org.hl7.fhir.r4.model.Patient();
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        return patient;
-    }
-
-    private org.hl7.fhir.r5.model.Patient getR5Patient() {
-        org.hl7.fhir.r5.model.Patient patient = new org.hl7.fhir.r5.model.Patient();
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        return patient;
-    }
-}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatTest.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatTest.java
deleted file mode 100644
index b2a4193..0000000
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatTest.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.quarkus.component.fhir.it;
-
-import ca.uhn.fhir.context.FhirContext;
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.RestAssured;
-import io.restassured.http.ContentType;
-import org.apache.camel.quarkus.component.fhir.FhirFlags;
-import org.apache.camel.quarkus.test.EnabledIf;
-import org.hl7.fhir.dstu3.model.Patient;
-import org.jboss.logging.Logger;
-import org.junit.jupiter.api.Test;
-
-@QuarkusTest
-class FhirDataformatTest {
-    private static final Logger LOG = Logger.getLogger(FhirDataformatTest.class);
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu2Enabled.class)
-    public void jsonDstu2() {
-        LOG.info("Running DSTU2 JSON test");
-
-        final ca.uhn.fhir.model.dstu2.resource.Patient patient = getDstu2Patient();
-        final String patientString = FhirContext.forDstu2().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/dstu2/fhir2json")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu2Enabled.class)
-    public void xmlDstu2() {
-        LOG.info("Running DSTU2 XML test");
-
-        final ca.uhn.fhir.model.dstu2.resource.Patient patient = getDstu2Patient();
-        final String patientString = FhirContext.forDstu2().newXmlParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.XML).body(patientString).post("/dstu2/fhir2xml")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu3Enabled.class)
-    public void jsonDstu3() {
-        LOG.info("Running DSTU3 JSON test");
-
-        final Patient patient = getDstu3Patient();
-        final String patientString = FhirContext.forDstu3().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/dstu3/fhir2json")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.Dstu3Enabled.class)
-    public void xmlDstu3() {
-        LOG.info("Running DSTU3 XML test");
-
-        final Patient patient = getDstu3Patient();
-        final String patientString = FhirContext.forDstu3().newXmlParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.XML).body(patientString).post("/dstu3/fhir2xml")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.R4Enabled.class)
-    public void jsonR4() {
-        LOG.info("Running R4 JSON test");
-
-        final org.hl7.fhir.r4.model.Patient patient = getR4Patient();
-        final String patientString = FhirContext.forR4().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/r4/fhir2json")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.R4Enabled.class)
-    public void xmlR4() {
-        LOG.info("Running R4 XML test");
-
-        final org.hl7.fhir.r4.model.Patient patient = getR4Patient();
-        final String patientString = FhirContext.forR4().newXmlParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.XML).body(patientString).post("/r4/fhir2xml")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.R5Enabled.class)
-    public void jsonR5() {
-        LOG.info("Running R5 JSON test");
-
-        final org.hl7.fhir.r5.model.Patient patient = getR5Patient();
-        final String patientString = FhirContext.forR5().newJsonParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.JSON).body(patientString).post("/r5/fhir2json")
-                .then().statusCode(201);
-    }
-
-    @Test
-    @EnabledIf(FhirFlags.R5Enabled.class)
-    public void xmlR5() {
-        LOG.info("Running R5 XML test");
-
-        final org.hl7.fhir.r5.model.Patient patient = getR5Patient();
-        final String patientString = FhirContext.forR5().newXmlParser().encodeResourceToString(patient);
-
-        RestAssured.given()
-                .contentType(ContentType.XML).body(patientString).post("/r5/fhir2xml")
-                .then().statusCode(201);
-    }
-
-    private ca.uhn.fhir.model.dstu2.resource.Patient getDstu2Patient() {
-        ca.uhn.fhir.model.dstu2.resource.Patient patient = new ca.uhn.fhir.model.dstu2.resource.Patient();
-        patient.addName().addGiven("Sherlock").addFamily("Holmes");
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        return patient;
-    }
-
-    private org.hl7.fhir.dstu3.model.Patient getDstu3Patient() {
-        org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        return patient;
-    }
-
-    private org.hl7.fhir.r4.model.Patient getR4Patient() {
-        org.hl7.fhir.r4.model.Patient patient = new org.hl7.fhir.r4.model.Patient();
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        return patient;
-    }
-
-    private org.hl7.fhir.r5.model.Patient getR5Patient() {
-        org.hl7.fhir.r5.model.Patient patient = new org.hl7.fhir.r5.model.Patient();
-        patient.addAddress().addLine("221b Baker St, Marylebone, London NW1 6XE, UK");
-        patient.addName().addGiven("Sherlock").setFamily("Holmes");
-        return patient;
-    }
-}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2IT.java
similarity index 82%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2IT.java
index 27d3862..3809920 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2IT.java
@@ -17,8 +17,11 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import io.quarkus.test.junit.NativeImageTest;
+import org.apache.camel.quarkus.component.fhir.it.util.Dstu2Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
 @NativeImageTest
-class FhirClientIT extends FhirClientTest {
+@EnabledIf(Dstu2Enabled.class)
+class FhirDstu2IT extends FhirDstu2Test {
 
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Test.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Test.java
new file mode 100644
index 0000000..35d8947
--- /dev/null
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu2Test.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.fhir.it;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
+import io.quarkus.test.common.http.TestHTTPEndpoint;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.apache.camel.quarkus.component.fhir.it.util.Dstu2Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
+
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@QuarkusTestResource(value = FhirTestResource.class, initArgs = @ResourceArg(name = "fhirVersion", value = "DSTU2"))
+@TestHTTPEndpoint(FhirDstu2Resource.class)
+@EnabledIf(Dstu2Enabled.class)
+class FhirDstu2Test extends AbstractFhirTest {
+
+    public void capabilities(String encodeAs) {
+        RestAssured.given()
+                .queryParam("encodeAs", encodeAs)
+                .get("/capabilities")
+                .then()
+                .statusCode(204);
+    }
+
+    public void metaGetFromServer() {
+        RestAssured.given()
+                .get("/meta/getFromServer")
+                .then()
+                .statusCode(200)
+                .body(is("0"));
+    }
+}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3IT.java
similarity index 82%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3IT.java
index 27d3862..5c89c81 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3IT.java
@@ -17,8 +17,11 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import io.quarkus.test.junit.NativeImageTest;
+import org.apache.camel.quarkus.component.fhir.it.util.Dstu3Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
 @NativeImageTest
-class FhirClientIT extends FhirClientTest {
+@EnabledIf(Dstu3Enabled.class)
+class FhirDstu3IT extends FhirDstu3Test {
 
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Test.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Test.java
new file mode 100644
index 0000000..2d4ec04
--- /dev/null
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDstu3Test.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.fhir.it;
+
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
+import io.quarkus.test.common.http.TestHTTPEndpoint;
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.apache.camel.quarkus.component.fhir.it.util.Dstu3Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
+
+import static org.hamcrest.Matchers.is;
+
+@QuarkusTest
+@QuarkusTestResource(value = FhirTestResource.class, initArgs = @ResourceArg(name = "fhirVersion", value = "DSTU3"))
+@TestHTTPEndpoint(FhirDstu3Resource.class)
+@EnabledIf(Dstu3Enabled.class)
+class FhirDstu3Test extends AbstractFhirTest {
+
+    @Override
+    public void metaGetFromServer() {
+        RestAssured.given()
+                .post("/meta")
+                .then()
+                .statusCode(200)
+                .body(is("1"));
+
+        RestAssured.given()
+                .get("/meta/getFromServer")
+                .then()
+                .statusCode(200)
+                .body(is("1"));
+    }
+}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4IT.java
similarity index 83%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4IT.java
index 27d3862..d19d50b 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4IT.java
@@ -17,8 +17,11 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import io.quarkus.test.junit.NativeImageTest;
+import org.apache.camel.quarkus.component.fhir.it.util.R4Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
 @NativeImageTest
-class FhirClientIT extends FhirClientTest {
+@EnabledIf(R4Enabled.class)
+class FhirR4IT extends FhirR4Test {
 
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Test.java
similarity index 61%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Test.java
index 27d3862..cffbc85 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR4Test.java
@@ -16,9 +16,17 @@
  */
 package org.apache.camel.quarkus.component.fhir.it;
 
-import io.quarkus.test.junit.NativeImageTest;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
+import io.quarkus.test.common.http.TestHTTPEndpoint;
+import io.quarkus.test.junit.QuarkusTest;
+import org.apache.camel.quarkus.component.fhir.it.util.R4Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
+@QuarkusTest
+@QuarkusTestResource(value = FhirTestResource.class, initArgs = @ResourceArg(name = "fhirVersion", value = "R4"))
+@TestHTTPEndpoint(FhirR4Resource.class)
+@EnabledIf(R4Enabled.class)
+class FhirR4Test extends AbstractFhirTest {
 
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5IT.java
similarity index 83%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5IT.java
index d6b0209..30a5fa9 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5IT.java
@@ -17,7 +17,11 @@
 package org.apache.camel.quarkus.component.fhir.it;
 
 import io.quarkus.test.junit.NativeImageTest;
+import org.apache.camel.quarkus.component.fhir.it.util.R5Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
 @NativeImageTest
-class FhirDataformatIT extends FhirDataformatTest {
+@EnabledIf(R5Enabled.class)
+class FhirR5IT extends FhirR5Test {
+
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Test.java
similarity index 61%
rename from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java
rename to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Test.java
index d6b0209..11cf9e9 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirDataformatIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirR5Test.java
@@ -16,8 +16,16 @@
  */
 package org.apache.camel.quarkus.component.fhir.it;
 
-import io.quarkus.test.junit.NativeImageTest;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
+import io.quarkus.test.common.http.TestHTTPEndpoint;
+import io.quarkus.test.junit.QuarkusTest;
+import org.apache.camel.quarkus.component.fhir.it.util.R5Enabled;
+import org.apache.camel.quarkus.test.EnabledIf;
 
-@NativeImageTest
-class FhirDataformatIT extends FhirDataformatTest {
+@QuarkusTest
+@QuarkusTestResource(value = FhirTestResource.class, initArgs = @ResourceArg(name = "fhirVersion", value = "R5"))
+@TestHTTPEndpoint(FhirR5Resource.class)
+@EnabledIf(R5Enabled.class)
+class FhirR5Test extends AbstractFhirTest {
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirTestResource.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirTestResource.java
index ff9627c..fb80a34 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirTestResource.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirTestResource.java
@@ -17,41 +17,58 @@
 
 package org.apache.camel.quarkus.component.fhir.it;
 
+import java.util.Collections;
 import java.util.Map;
 
 import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+import org.apache.camel.quarkus.component.fhir.it.util.FhirTestHelper;
 import org.apache.camel.util.CollectionHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testcontainers.containers.GenericContainer;
 import org.testcontainers.containers.wait.strategy.Wait;
-import org.testcontainers.utility.TestcontainersConfiguration;
 
 public class FhirTestResource implements QuarkusTestResourceLifecycleManager {
     private static final Logger LOGGER = LoggerFactory.getLogger(FhirTestResource.class);
+    private static final String FHIR_DSTU_CONTAINER_TAG = "v4.2.0";
+    private static final String FHIR_DSTU_CONTEXT_PATH = "/hapi-fhir-jpaserver/fhir";
+    private static final String FHIR_R_CONTAINER_TAG = "v5.7.0";
+    private static final String FHIR_R_CONTEXT_PATH = "/fhir";
     private static final int CONTAINER_PORT = 8080;
-    private static final String CONTAINER_IMAGE = "quay.io/lburgazzoli/hapi-fhir-jpaserver-starter:4.1.0";
 
+    private FhirVersion fhirVersion;
     private GenericContainer container;
 
     @Override
+    public void init(Map<String, String> initArgs) {
+        this.fhirVersion = FhirVersion.valueOf(initArgs.get("fhirVersion"));
+    }
+
+    @Override
     public Map<String, String> start() {
-        LOGGER.info(TestcontainersConfiguration.getInstance().toString());
+        if (this.fhirVersion == null) {
+            return Collections.emptyMap();
+        }
+
+        if (!FhirTestHelper.isFhirVersionEnabled(fhirVersion.name())) {
+            LOGGER.info("FHIR version {} is disabled. No hapi test container will be started for it.",
+                    fhirVersion.simpleVersion());
+            return Collections.emptyMap();
+        }
 
         try {
-            container = new GenericContainer(CONTAINER_IMAGE)
+            LOGGER.info("FHIR version {} is enabled. Starting hapi test container for it.", fhirVersion.simpleVersion());
+            String imageName = fhirVersion.getContainerImageName();
+            container = new GenericContainer(imageName)
                     .withExposedPorts(CONTAINER_PORT)
-                    .withEnv("HAPI_FHIR_VERSION", "DSTU3")
-                    .waitingFor(Wait.forListeningPort());
+                    .withEnv("HAPI_FHIR_VERSION", fhirVersion.name())
+                    .waitingFor(Wait.forHttp(fhirVersion.getHealthEndpointPath()));
 
             container.start();
 
             return CollectionHelper.mapOf(
-                    "camel.fhir.test-url",
-                    String.format(
-                            "http://%s:%d/hapi-fhir-jpaserver/fhir",
-                            container.getContainerIpAddress(),
-                            container.getMappedPort(CONTAINER_PORT)));
+                    String.format("camel.fhir.%s.test-url", fhirVersion.simpleVersion()),
+                    fhirVersion.getServerUrl(container.getContainerIpAddress(), container.getMappedPort(CONTAINER_PORT)));
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
@@ -67,4 +84,43 @@ public class FhirTestResource implements QuarkusTestResourceLifecycleManager {
             // ignored
         }
     }
+
+    enum FhirVersion {
+        DSTU2(FHIR_DSTU_CONTAINER_TAG, FHIR_DSTU_CONTEXT_PATH),
+        DSTU3(FHIR_DSTU_CONTAINER_TAG, FHIR_DSTU_CONTEXT_PATH),
+        R4(FHIR_R_CONTAINER_TAG, FHIR_R_CONTEXT_PATH),
+        R5(FHIR_R_CONTAINER_TAG, FHIR_R_CONTEXT_PATH);
+
+        private final String fhirImageTag;
+        private final String contextPath;
+
+        FhirVersion(String fhirImageTag, String contextPath) {
+            this.fhirImageTag = fhirImageTag;
+            this.contextPath = contextPath;
+        }
+
+        public String simpleVersion() {
+            return this.name().toLowerCase();
+        }
+
+        public String getFhirContainerImageTag() {
+            return fhirImageTag;
+        }
+
+        public String getContextPath() {
+            return contextPath;
+        }
+
+        public String getContainerImageName() {
+            return String.format("hapiproject/hapi:%s", getFhirContainerImageTag());
+        }
+
+        public String getServerUrl(String host, int port) {
+            return String.format("http://%s:%d%s", host, port, getContextPath());
+        }
+
+        public String getHealthEndpointPath() {
+            return String.format("%s/metadata", getContextPath());
+        }
+    }
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu2Enabled.java
similarity index 74%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu2Enabled.java
index 27d3862..bd0cc4e 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu2Enabled.java
@@ -14,11 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.fhir.it;
+package org.apache.camel.quarkus.component.fhir.it.util;
 
-import io.quarkus.test.junit.NativeImageTest;
-
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
+import java.util.function.BooleanSupplier;
 
+public class Dstu2Enabled implements BooleanSupplier {
+    @Override
+    public boolean getAsBoolean() {
+        return FhirTestHelper.isFhirVersionEnabled("DSTU2");
+    }
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu3Enabled.java
similarity index 74%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu3Enabled.java
index 27d3862..94c7510 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/Dstu3Enabled.java
@@ -14,11 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.fhir.it;
+package org.apache.camel.quarkus.component.fhir.it.util;
 
-import io.quarkus.test.junit.NativeImageTest;
-
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
+import java.util.function.BooleanSupplier;
 
+public class Dstu3Enabled implements BooleanSupplier {
+    @Override
+    public boolean getAsBoolean() {
+        return FhirTestHelper.isFhirVersionEnabled("DSTU3");
+    }
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/FhirTestHelper.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/FhirTestHelper.java
new file mode 100644
index 0000000..aad2b64
--- /dev/null
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/FhirTestHelper.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.fhir.it.util;
+
+import java.io.IOException;
+import java.util.Properties;
+
+import org.apache.camel.quarkus.component.fhir.it.AbstractFhirRouteBuilder;
+
+public final class FhirTestHelper {
+
+    private FhirTestHelper() {
+        // Utility class
+    }
+
+    public static boolean isFhirVersionEnabled(String version) {
+        try {
+            Properties properties = new Properties();
+            properties.load(AbstractFhirRouteBuilder.class.getResourceAsStream("/application.properties"));
+            String key = "quarkus.camel.fhir.enable-" + version.toLowerCase();
+            String envKey = key.toUpperCase().replace('.', '_');
+            String value = (String) properties.getOrDefault(key, System.getProperty(key, System.getenv(envKey)));
+            return Boolean.valueOf(value);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R4Enabled.java
similarity index 75%
copy from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
copy to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R4Enabled.java
index 27d3862..180a8bd 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R4Enabled.java
@@ -14,11 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.fhir.it;
+package org.apache.camel.quarkus.component.fhir.it.util;
 
-import io.quarkus.test.junit.NativeImageTest;
-
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
+import java.util.function.BooleanSupplier;
 
+public class R4Enabled implements BooleanSupplier {
+    @Override
+    public boolean getAsBoolean() {
+        return FhirTestHelper.isFhirVersionEnabled("R4");
+    }
 }
diff --git a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R5Enabled.java
similarity index 75%
rename from integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
rename to integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R5Enabled.java
index 27d3862..ff64f54 100644
--- a/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/FhirClientIT.java
+++ b/integration-tests/fhir/src/test/java/org/apache/camel/quarkus/component/fhir/it/util/R5Enabled.java
@@ -14,11 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.quarkus.component.fhir.it;
+package org.apache.camel.quarkus.component.fhir.it.util;
 
-import io.quarkus.test.junit.NativeImageTest;
-
-@NativeImageTest
-class FhirClientIT extends FhirClientTest {
+import java.util.function.BooleanSupplier;
 
+public class R5Enabled implements BooleanSupplier {
+    @Override
+    public boolean getAsBoolean() {
+        return FhirTestHelper.isFhirVersionEnabled("R5");
+    }
 }