Skip to content

FHIR R5 Interoperability Layer

CIPRIAN STEFAN PLESCA edited this page Aug 2, 2026 · 1 revision

4. The FHIR R5 Interoperability Layer

The interoperability layer is centered on two collaborating components: FHIRBundleBuilder and related functions in fhir/builders.py, which construct well-formed FHIR JSON resources and a CapabilityStatement; and FHIRStore in fhir/repository.py, which owns the in-memory persistence, versioning, and search behavior. The API layer never manipulates raw resource dictionaries directly — every request passes through the store's typed interface, which is what allows the resource-type/URL consistency check, version increment, and audit emission to be enforced in one place regardless of which route triggered them.

4.1 Resource Lifecycle and Optimistic Concurrency

Figure 3 traces a create-then-update sequence end to end. On creation, FHIRStore validates that the URL's resource type matches the payload's resourceType field, assigns a server-generated identifier, sets meta.versionId to 1, and appends a corresponding entry to the audit chain before returning a 201 response with a weak ETag. On update, the client is expected to supply an If-Match header carrying the version it last observed; the store compares this against the currently stored versionId and raises a VersionConflict, mapped by the API layer to an HTTP 409 response with a FHIR OperationOutcome body, whenever the two disagree. This is the standard optimistic-concurrency pattern FHIR servers use to prevent silent lost updates when two clients race to modify the same resource, implemented here without a database transaction because the store itself is single-process and lock-protected.

sequenceDiagram
    participant C as Client
    participant Auth as APIKeyAuthenticator
    participant R as FHIR Route
    participant S as FHIRStore
    participant A as AuditChain

    C->>Auth: POST /fhir/R5/Patient (X-API-Key)
    Auth-->>R: key verified (constant-time compare)
    R->>S: create(resourceType, payload)
    S->>S: validate resourceType == payload.resourceType
    S->>S: assign server id, meta.versionId = 1
    S->>A: append(action=create, resource=Patient/id)
    S-->>R: resource, ETag W/"1"
    R-->>C: 201 Created, ETag: W/"1"

    C->>Auth: PUT /fhir/R5/Patient/id (If-Match: W/"1")
    Auth-->>R: key verified
    R->>S: update(id, payload, if_match="1")
    alt version matches
        S->>S: versionId += 1
        S->>A: append(action=update, resource=Patient/id)
        S-->>R: resource, ETag W/"2"
        R-->>C: 200 OK, ETag: W/"2"
    else version stale
        S-->>R: raise VersionConflict
        R-->>C: 409 Conflict, OperationOutcome
    end
Loading

Figure 3. Sequence diagram of a FHIR create-then-update lifecycle, showing the authentication check, resource-type validation, version-conflict handling, and audit emission.

4.2 Data Rules and Deep Copying

Because FHIRStore holds resources purely in process memory, its deep-copy discipline is what prevents a caller from mutating a resource through an aliased reference after it has been "persisted." The architecture documentation is explicit that this store is intentionally replaceable with a real FHIR repository, and that the project's data rules — synthetic data only, no PHI in contract state or events, opaque identifiers when integrating externally — apply to the repository and its CI as a whole, not merely to this one module.

4.3 Search and the CapabilityStatement

MedIntelOS implements a narrow, exact-match search subset rather than the full FHIR search grammar (chained parameters, modifiers, _include/_revinclude, and so on). The /fhir/R5/metadata endpoint returns a CapabilityStatement generated from the same code that implements the behavior it describes, which is a meaningful correctness property: a CapabilityStatement is only useful to an integrating client if it does not overstate what the server can do, and generating it programmatically from the implemented route set is one concrete way to keep the two in sync.

4.4 Example Interaction

Creating a synthetic FHIR Patient resource against the reference API illustrates the full request shape:

POST /fhir/R5/Patient HTTP/1.1
Content-Type: application/fhir+json
X-API-Key: <development key>

{"resourceType": "Patient", "name": [{"family": "Doe"}], "gender": "unknown"}
HTTP/1.1 201 Created
ETag: W/"1"
Location: /fhir/R5/Patient/<generated-id>

4.5 Boundary Summary

Table 2. FHIR capability status

Capability Status
Resource CRUD with server-assigned IDs Implemented
Optimistic concurrency via If-Match / ETag Implemented
CapabilityStatement generation Implemented
Exact-match search subset Implemented
Profile / StructureDefinition validation Not implemented
Terminology binding and validation Not implemented
Durable persistence across process restarts Not implemented
Bulk Data / subscriptions / SMART App Launch Not implemented

The pattern that emerges — a correct, well-tested implementation of a deliberately narrow slice, paired with an accurate statement of what lies outside that slice — recurs in every subsequent pillar examined in this wiki.


Previous: ← System Architecture Overview · Next: The Clinical Decision Support Subsystem →

Clone this wiki locally