FHIR Connect

Note

Before creating or modifying mappings in OpenFHIR, users must familiarize themselves with the FHIR Connect specification.

Understanding OpenFHIR Mappings

Importance of Proper Mapping in OpenFHIR

OpenFHIR is a powerful engine designed to process and transform healthcare data using FHIR (Fast Healthcare Interoperability Resources). However, for OpenFHIR to function correctly, it is essential that all mappings are defined according to the FHIR Connect specification. Properly structured mappings ensure interoperability, consistency, and reliable data transformation within the OpenFHIR ecosystem.

Why Adhering to FHIR Connect Specification Matters

The FHIR Connect specification establishes clear guidelines on how mappings should be structured to enable seamless data exchange. If mappings are not correctly expressed according to this specification, OpenFHIR may not operate as expected, leading to errors, incomplete transformations, or failed interoperability between systems.

By following the FHIR Connect specification:

  • Data transformations are predictable and reliable.

  • Integration between different healthcare systems remains seamless.

  • The engine can properly interpret and execute mappings without errors.

Engine-specific behaviour

Selecting a coding with fhirCondition

A DV_CODED_TEXT can carry more than one code: its own defining_code and any number of TERM_MAPPINGs (_mapping:N/target in the flat format). $tofhir parses all of them into one CodeableConcept, the element’s own code first and the mapping targets after it. $toopenehr does the reverse, writing the first coding as the element’s code and the rest as TERM_MAPPINGs.

A fhirCondition whose targetRoot addresses those codings selects which of them cross to FHIR. In the $toopenehr direction it filters the codings the FHIR path yields, as any condition does; in the $tofhir direction it keeps only the codings that satisfy it. The same condition therefore reads the same way in both directions.

The condition is coding-level when its targetRoot is

  • the mapped path’s coding for a CodeableConcept target (with.fhir: $resource.route and targetRoot: $resource.route.coding), or

  • the mapped path itself for a Coding target (with.fhir: $resource.route.coding and targetRoot: $resource.route.coding).

A condition anchored anywhere else (a sibling, a parent, an extension a child mapping writes) leaves the codings alone. The operators are one of and not of; empty / not empty are presence gates and never select.

Inside a followedBy block spell the targetRoot the way the child’s own path is spelled, relative to the parent: a child with.fhir: route under a $resource.dosageInstruction parent takes targetRoot: route.coding. A $resource.-anchored targetRoot is resolved against the parent’s path there, exactly like a $resource.-anchored child path, so it would address a different element.

The typical use is a source system that sends its local code with the standard equivalent as a TERM_MAPPING, while the target profile allows exactly one coding of the standard system. The flat composition carries

{
  "ordination/medication_order/order:0/route|code": "3.0000",
  "ordination/medication_order/order:0/route|value": "Intravenös",
  "ordination/medication_order/order:0/route|terminology": "Cytodos",
  "ordination/medication_order/order:0/route/_mapping:0|match": "=",
  "ordination/medication_order/order:0/route/_mapping:0/target|code": "47625008",
  "ordination/medication_order/order:0/route/_mapping:0/target|terminology": "SNOMED-CT"
}

and the mapping picks the SNOMED coding:

- name: "route"
  with:
    fhir: "$resource.dosageInstruction.route.coding"
    openehr: "$archetype/activities[at0001]/description[at0002]/items[at0091]"
  fhirCondition:
    targetRoot: "$resource.dosageInstruction.route.coding"
    targetAttribute: "system"
    operator: "one of"
    criteria: "http://snomed.info/sct"
  terminology:
    type: "local"
    conceptmap: "http://openfhir.com/ConceptMap/snomed-passthrough"

The condition is evaluated after terminology translation, so its criteria are the FHIR systems that will actually be written. Here the "*" passthrough ConceptMap rewrites the openEHR terminology id SNOMED-CT to http://snomed.info/sct (see Terminology); without a ConceptMap the coding keeps the openEHR terminology id as its system, and the criteria has to name that instead.

Selection is not a gate. When no coding satisfies the condition the codings are written unchanged and a debug line is logged — a mapping whose condition describes a value a child manual writes later (the usual bidirectional idiom for clinicalStatus and the like) keeps working as before.

On the way back, $toopenehr sees only the codings that were written, so a many-to-one selection is lossy: the Cytodos code above is not recovered from the SNOMED coding unless a ConceptMap maps it back.