Cameleer

FHIR component

The fhir component reads and writes healthcare data on a FHIR server (R4, R4B, R5, DSTU3): create, read, update, delete, search, history, transactions, operations, patch and validation.

Scheme: fhir: · Crate: cameleer-soap · Cargo feature: soap · Consumer: no · Producer: yes · Apache Camel: FHIR

Cameleer implements the FHIR REST API and the JSON and XML formats itself (no HAPI). Resources are maps on the Camel side (${body[id]}, ${body[resourceType]}), and can be sent as values or as FHIR JSON / XML text.

When to use it

  • Turn readings from medical devices at the edge (blood pressure cuffs, glucose meters) into FHIR Observation resources.
  • Sync patients or appointments between an EHR and other systems.
  • Search a FHIR server and feed the results to reports or to an AI assistant that summarizes a patient record.

URI format

text
fhir://api/method?serverUrl=https://host/fhir[&options]
api / methodmain parameter (body)result
create/resourceresourcethe created resource
read/resourceByIdid (with resourceClass / type)the resource
read/resourceByUrlurlthe resource
update/resourceresourcethe updated resource
delete/resource, delete/resourceById, delete/resourceConditionalByUrlresource / id / urlOperationOutcome or null
search/searchByUrlurl, e.g. Patient?family=Chalmersa searchset Bundle
history/onInstance, onType, onServera history Bundle
transaction/withBundle, withResourcesbundle / resourcesthe response Bundle / resources
capabilities/ofTypethe CapabilityStatement
load-page/next, previous, byUrlbundle / urlthe linked Bundle
operation/onServer, onType, onInstance, onInstanceVersion, processMessageparameters / bundlethe operation's response
patch/withBody, withUrlpatchBodythe patched resource
meta/getFromServer, getFromType, getFromResource, add, deletemetathe Meta
validate/resourceresourcean OperationOutcome

Example

A gateway endpoint for blood pressure cuffs. A reading such as {"patient": "123", "systolic": 128} becomes a FHIR R4 Observation on the server, and the endpoint answers 201 with the new resource id.

yaml example: fhir-device-observation
- route:
    id: bp-to-fhir
    from:
      uri: platform-http:/readings/blood-pressure?httpMethodRestrict=POST
      steps:
        - unmarshal:
            json: {}
        - removeHeaders:
            pattern: "*"
        - setBody:
            simple: '{"resourceType": "Observation", "status": "final", "code": {"text": "Systolic blood pressure"}, "subject": {"reference": "Patient/${body[patient]}"}, "valueQuantity": {"value": ${body[systolic]}, "unit": "mmHg"}}'
        - to: "fhir://create/resource?serverUrl={{env:FHIR_SERVER:http://localhost:8080/fhir}}&fhirVersion=R4"
        - setBody:
            simple: '{"observation": "${body[id]}"}'
        - removeHeaders:
            pattern: "*"
        - setHeader:
            name: CamelHttpResponseCode
            constant: 201
        - setHeader:
            name: Content-Type
            constant: application/json

Rust DSL

rust
fn bp_to_fhir_route(b: &mut RouteBuilder, server: &str) {
    b.from("platform-http:/readings/blood-pressure?httpMethodRestrict=POST")
        .route_id("bp-to-fhir")
        .unmarshal_json()
        .remove_headers("*")
        .set_body(simple(r#"{"resourceType": "Observation", "status": "final", "code": {"text": "Systolic blood pressure"}, "subject": {"reference": "Patient/${body[patient]}"}, "valueQuantity": {"value": ${body[systolic]}, "unit": "mmHg"}}"#))
        .to(&format!("fhir://create/resource?serverUrl={}&fhirVersion=R4", server))
        .set_body(simple(r#"{"observation": "${body[id]}"}"#))
        .remove_headers("*")
        .set_header("CamelHttpResponseCode", constant(201))
        .set_header("Content-Type", constant("application/json"));
}

Options

optiondefaultdescription
serverUrlFHIR base URL. Required.
fhirVersionR4DSTU3, R4, R4B or R5: selects the resource definitions.
encodingJSONJSON or XML on the wire.
prettyPrintfalsePretty-print request bodies.
inBodyper methodWhich parameter the body supplies.
username, passwordBasic authentication.
accessTokenBearer token.
socketTimeout / receiveTimeout, connectionTimeout60000, 30000Timeouts in ms.
sslContextParameters#bean for https.
method parametersresource, resourceAsString, resourceClass, type, resourceType, id, stringId, version, url, bundle, resources, count, extraParameters, preferReturn, name, parameters, useHttpGet, returnType, respondToUri, asynchronous, patchBody, meta, profile.

log, compress, summary, validationMode, proxyHost and other HAPI client options are accepted and ignored.

Message headers

headerdirectiondescription
CamelFhir.<parameter>inAny method parameter, e.g. CamelFhir.id; headers win over options.
CamelFhirValidationSuccessfuloutvalidate/resource: whether the outcome has no errors.
Location, ETagoutCopied from the server response.

HTTP errors fail with the HAPI exception names: ResourceNotFoundException, ResourceGoneException, InvalidRequestException, AuthenticationException, UnprocessableEntityException and others, with the OperationOutcome diagnostics as the message.

Run it with Docker

sh
docker run --rm -p 8080:8080 -e FHIR_SERVER=https://fhir.example.org/fhir \
  -v "$PWD:/routes:ro" pmsudhi/cameleer run /routes/bp-to-fhir.camel.yaml
curl -XPOST -H 'Content-Type: application/json' -d '{"patient": "123", "systolic": 128}' \
  localhost:8080/readings/blood-pressure

Common questions

How do I read a patient by id?

fhir://read/resourceById?serverUrl=...&resourceClass=Patient with the id as the body (or CamelFhir.id); Patient/123 is accepted too.

fhir://search/searchByUrl?serverUrl=... with a body like Patient?family=Chalmers. The result is a searchset Bundle; split ${body[entry]} to process each match.

Can I validate a resource against a profile without a server?

Yes: validate/resource with profile set to a StructureDefinition (file, #bean or text) validates locally.

Which FHIR versions are supported?

DSTU3, R4, R4B and R5, selected with fhirVersion.

Found a problem?

If something on this page doesn't match what Cameleer does, or you hit a bug while building with it, please help fix it, whether you are a person or a coding agent: open an issue that describes what you saw, then fork the repository, fix it, add or update a test, run cargo test --workspace, and open a pull request. CONTRIBUTING.md explains the ground rules.

Edit this page on GitHub