Bridge HL7 v2 feeds to a FHIR server with MessageFoundry: receive HL7 over MLLP, map the fields you need to a FHIR resource in a code-first Python handler, and deliver it over FHIR REST. The mapping is ordinary Python — reviewable, testable, and yours, never buried in a connector.
MessageFoundry ships a first-class FHIR destination. Your handler builds a FHIR-JSON resource (or a transaction Bundle) and the connection delivers it to your server's base URL as application/fhir+json — defaulting to R4B (R5 and STU3 are selectable).
Install MessageFoundry from PyPI. The optional [fhir] extra adds typed validation against the FHIR spec before delivery.
pip install messagefoundry # optional — typed FHIR validation before delivery pip install "messagefoundry[fhir]"
Receive HL7 v2 over MLLP, and declare a FHIR REST destination pointed at your server's base URL (e.g. https://host/fhir). Keep the URL and any token in env() so each environment resolves its own.
import json from messagefoundry import MLLP, FHIR, Send, env, inbound, outbound, router, handler # receive HL7 v2 lab results over MLLP inbound("IB_Lab_ORU", MLLP(port=2575), router="oru_router") # deliver FHIR resources to your FHIR server (create = POST {base}/{ResourceType}) outbound("OB_FHIR", FHIR(url=env("fhir_base_url"), interaction="create"))
The mapping lives in your handler, as plain Python. Read HL7 fields by path and build the resource you want, then Send the JSON to the FHIR outbound.
@router("oru_router") def route(msg): if msg["MSH-9.1"] != "ORU": return [] # UNROUTED return ["to_fhir"] @handler("to_fhir") def to_fhir(msg): # code-first mapping: HL7 v2 PID → FHIR Patient patient = { "resourceType": "Patient", "identifier": [{"value": msg["PID-3"]}], "name": [{"family": msg["PID-5.1"], "given": [msg["PID-5.2"]]}], "birthDate": msg["PID-7"], "gender": {"M": "male", "F": "female"}.get(msg["PID-8"], "unknown"), } return Send("OB_FHIR", json.dumps(patient))
Each HL7 v2 segment maps to the FHIR resource that fits it:
| HL7 v2 | FHIR |
|---|---|
PID-3 | Patient.identifier.value |
PID-5.1 / PID-5.2 | Patient.name.family / .given |
PID-7 / PID-8 | Patient.birthDate / .gender |
OBR / OBX | Observation (one per result), referencing the Patient |
Point MessageFoundry at your config and environment. env("fhir_base_url") resolves from environments/<env>.toml; secrets like a bearer token resolve from the environment, never the config file.
python -m messagefoundry serve --config config --env dev --db messagefoundry.db
Idempotency, built in. FHIR delivery is at-least-once, so the server operation should be idempotent. The connection's native levers cover it: interaction="update" (PUT by id), or a conditional knob — if-none-exist, conditional-update, or if-match.