Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The FHIRconnect operations

FerroBRIDGE serves the two operations the FHIRconnect specification defines for its engine: $tofhir turns an openEHR composition into FHIR resources, and $toopenehr turns FHIR resources back into a composition. Both are pure transformations. Neither reaches a CDR, and neither changes server state, so you can call them from a facade, a test harness or a shell.

The chapter is a draft

The REST API chapter is pull request #93 of the FHIRconnect specification and is not part of any release. FerroBRIDGE implements it at the pinned commit recorded in docs/VERSIONS.md, vendors the chapter and its FSH operation definitions, and labels the wire tests draft. When the chapter merges, the pin moves and every difference is re-adjudicated.

Turning the lane on

Configure a mapping set. [mappings] directory names the tree of FHIRconnect mapping files. The operational templates they compile against come from [mappings] templates when it names a directory, and otherwise from the [cdr], which serves each template a context names. Everything is read once at boot, so a mapping or a template that does not load stops the server rather than the first request that touches it. [operations] carries the lane switch and the values a run needs beside the payload. See Configuring the server.

Without [mappings], both operations answer 503 with an OperationOutcome.

POST /fhir/$tofhir

The body is a FHIR Parameters resource in application/fhir+json:

{
  "resourceType": "Parameters",
  "parameter": [
    { "name": "composition", "valueString": "<the composition as a JSON string>" },
    { "name": "templateId", "valueString": "Blood Pressure" },
    {
      "name": "context",
      "part": [
        { "name": "ehr_id", "valueString": "53d89df2-5501-4455-9a65-565a5d1ddb7c" },
        { "name": "patient", "valueReference": { "reference": "Patient/123" } },
        { "name": "who", "valueReference": { "reference": "Practitioner/456" } },
        { "name": "onBehalfOf", "valueReference": { "reference": "Organization/charite" } }
      ]
    }
  ]
}

The composition travels as a JSON string in either serialization. A canonical composition carries its template at archetype_details.template_id; a FLAT one carries none, so templateId is required with it and a FLAT payload without one answers 400 with the issue code required. When the payload and templateId both name a template and they disagree, the call is refused.

The answer is a collection Bundle carrying the mapped resources, exactly one Provenance, and an OperationOutcome entry when the run declared a loss.

POST /fhir/$toopenehr

The body is a FHIR Bundle, or a Parameters carrying it under bundle. The answer is a Parameters with the composition as a JSON string and an optional outcome. format selects the serialization: canonical by default, or flat.

FerroBRIDGE picks the mapping by the profiles the Bundle’s resources claim in meta.profile, narrowed by templateId when you supply one. A Bundle that references more than one subject, or that carries more than one resource of the mapped type, is refused: one Bundle maps to one composition.

Query parameters

templateId, format and ehr_id may travel in the query instead of the body. The two forms are equivalent, and the body wins when both carry the same field.

POST /fhir/$tofhir?templateId=KDS_Fall_einfach&ehr_id=53d89df2-5501-4455-9a65-565a5d1ddb7c

A structured value, a full Reference such as who or onBehalfOf, belongs in the body.

The direct form

When you have a composition and want a Bundle back, the wrapper buys you nothing. The chapter therefore allows an un-enveloped form, and marks it as a deliberate deviation from the FHIR operations framework that stays outside the FHIRconnect FHIR implementation guide:

POST /fhir/tofhir
Content-Type: application/openehr+json

{ "_type": "COMPOSITION", ... }
POST /fhir/toopenehr?format=flat
Content-Type: application/fhir+json

<a FHIR Bundle>

POST /fhir/tofhir answers the Bundle itself and POST /fhir/toopenehr answers the composition itself, with Content-Type: application/openehr+json. The media type is the one the chapter defines for openEHR canonical JSON, with the suffix ordering of RFC 6839 §4.

Discovering the operations

With the facade enabled beside this lane, GET /fhir/metadata declares both operations in CapabilityStatement.rest.operation, as tofhir and toopenehr with the canonical OperationDefinition URL of each. When the lane is off, the statement leaves them out. The direct forms are never declared: the request body is no FHIR resource and the response is no Parameters, so they fall outside the FHIR operations framework the statement describes, and the chapter keeps them out of the FHIRconnect implementation guide.

What a failure looks like

FerroBRIDGE is strict, which the chapter leaves open. A mapping that cannot be performed answers an OperationOutcome and no Bundle and no composition, so you can never mistake a partial result for a complete one. A run that succeeded but lost something reports each loss as an issue beside the result: information for a composition field the engine filled, warning for content that did not reach the output.

Every error is an OperationOutcome in application/fhir+json, with the R4 issue code that fits: required for a missing parameter, structure for a parameter the operation does not declare or one given twice, value for the wrong value type, not-found for a template or profile nothing answers, multiple-matches when several mappings answer and nothing pins the choice, business-rule for a Bundle with more than one subject, and processing for a mapping that did not run to completion. A body in any other media type answers 415.

Provenance on every run

Every $tofhir Bundle carries one Provenance describing the transformation: target references every mapped resource, recorded is the run time, agent.who is context.who or the configured Device reference, agent.onBehalfOf is context.onBehalfOf, and one entity with role = derivation names the composition the run read, by its uid when it carried one.

Resolving the patient

An openEHR composition identifies the patient through the EHR it belongs to, so mapping to FHIR means resolving an EHR identifier to a patient. That belongs to whatever owns patient identity in a deployment. context.patient is the caller’s fallback: FerroBRIDGE never requires it, and when you supply it, it takes precedence over the subject a mapping resolved on its own. Correctness then rests with you, because a wrong reference attaches clinical data to the wrong patient and nothing downstream catches it.