Convert HL7 v2 to FHIR in Python
Receive HL7 v2 over MLLP, map fields to a FHIR resource in a Python handler, and deliver it to a FHIR server.
The FHIR destination sends a FHIR-JSON resource or transaction Bundle built by your handler. It delivers to your server’s base URL as application/fhir+json. The default version is R4B; you can select R5 or STU3.
1. Install the engine
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]"
2. Declare an HL7 inbound and a FHIR outbound
Receive HL7 v2 over MLLP. Set the FHIR REST destination to your server’s base URL, such as https://host/fhir. Use env() for the URL and token so each environment resolves its own values.
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"))
3. Map HL7 fields to a FHIR resource
Write the mapping in your Python handler. Read HL7 fields by path, build the resource, then Send the JSON to the FHIR destination.
@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 |
4. Run the engine
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
FHIR delivery is at-least-once, so server operations must tolerate repeated requests without duplicate writes. Use interaction="update" for PUT by id. Conditional options include if-none-exist, conditional-update, and if-match.
Related guides
Frequently asked questions
Can MessageFoundry convert HL7 v2 to FHIR?
Yes. Receive HL7 v2 over MLLP and map the needed fields to a FHIR resource in a Python handler. Deliver it through a FHIR REST connection. Keep the mapping in version control and test it with your interface code.
Which FHIR version does MessageFoundry target?
The FHIR REST connection defaults to R4B; R5 and STU3 are selectable. It sends application/fhir+json to your server’s base URL using create (POST), update (PUT), or transaction/batch interactions.
Where does the HL7-to-FHIR mapping live?
Write the mapping in your Python handler. Read fields by path, such as PID-5.1 or OBR-25, and build the FHIR resource. Review and test it with the rest of your code.
How does MessageFoundry avoid duplicate FHIR writes?
FHIR delivery is at-least-once, so server operations must tolerate repeated requests without duplicate writes. Use interaction='update' for PUT by id, or a conditional option: if-none-exist, conditional-update, or if-match.