FHIR component
The
fhircomponent 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
Observationresources. - 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
fhir://api/method?serverUrl=https://host/fhir[&options]| api / method | main parameter (body) | result |
|---|---|---|
create/resource | resource | the created resource |
read/resourceById | id (with resourceClass / type) | the resource |
read/resourceByUrl | url | the resource |
update/resource | resource | the updated resource |
delete/resource, delete/resourceById, delete/resourceConditionalByUrl | resource / id / url | OperationOutcome or null |
search/searchByUrl | url, e.g. Patient?family=Chalmers | a searchset Bundle |
history/onInstance, onType, onServer | a history Bundle | |
transaction/withBundle, withResources | bundle / resources | the response Bundle / resources |
capabilities/ofType | the CapabilityStatement | |
load-page/next, previous, byUrl | bundle / url | the linked Bundle |
operation/onServer, onType, onInstance, onInstanceVersion, processMessage | parameters / bundle | the operation's response |
patch/withBody, withUrl | patchBody | the patched resource |
meta/getFromServer, getFromType, getFromResource, add, delete | meta | the Meta |
validate/resource | resource | an 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.
- 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/jsonRust DSL
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
| option | default | description |
|---|---|---|
serverUrl | FHIR base URL. Required. | |
fhirVersion | R4 | DSTU3, R4, R4B or R5: selects the resource definitions. |
encoding | JSON | JSON or XML on the wire. |
prettyPrint | false | Pretty-print request bodies. |
inBody | per method | Which parameter the body supplies. |
username, password | Basic authentication. | |
accessToken | Bearer token. | |
socketTimeout / receiveTimeout, connectionTimeout | 60000, 30000 | Timeouts in ms. |
sslContextParameters | #bean for https. | |
| method parameters | resource, 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
| header | direction | description |
|---|---|---|
CamelFhir.<parameter> | in | Any method parameter, e.g. CamelFhir.id; headers win over options. |
CamelFhirValidationSuccessful | out | validate/resource: whether the outcome has no errors. |
Location, ETag | out | Copied 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
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-pressureCommon 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.
How do I search?
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.
Related
- http, rest, platform-http.
- Data formats:
fhirJson,fhirXml. - Apache Camel: FHIR component.
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.