This guide outlines the practical steps and broader process used to implement a new HL7 message event to FHIR resource mapping. Resource mapping is declarative and utilizes yaml configuration files.
Implementation Steps include:
- Create an issue so your work can be tracked and you can get feedback and input. (See CONTRIBUTING.)
- What is it you're doing?
- 1 Adding new field mappings to an existing segment? Then:
- Review the official HL7 documentation for the target FHIR Resource.
- Modify the existing segment template and resource templates to map the HL7 fields to FHIR resources and data objects.
- Modify an existing segment test with new field / resource assertions
- 2 Adding new segments to an existing message trigger? Then:
- Review the official HL7 documentation for the target FHIR Resource.
- Modify the existing message template and resource templates to map the HL7 segments to FHIR resources and data objects.
- Modify an existing message test with new segment / resource assertions
- 3 Creating a new message / trigger? Then
- Validate your proposed new message/triggering event against HL7 documentation and try parsing it.
- Review the official HL7 documentation for the target FHIR Resource.
- Create a new message template
- Create new FHIR resource templates if necessary.
- Create the HL7 message template to support the message/trigger event to resource mapping.
- Implement tests for both the messages to resources and segment fields to resource data to validate mapping results.
- 1 Adding new field mappings to an existing segment? Then:
- Make a PR and request review (See CONTRIBUTING.)
- Suggestions for new developers
The Official FHIR documentation, provided by the HL7 organization, provides complete documentation for FHIR resources and the corresponding HL7 v2 mappings. The best place to start is by reviewing the resource index.
Each resource page contains field definitions (Example: Medication Resource), and HL7 v2 mappings (Example: Medication Resource). Review the documentation determine which FHIR resource fields to include. The FHIR specification supports numerous resources with a variety of fields. It is likely that a subset of fields are required for a given use-case.
Also, keep in mind the messages, structures, groups, and segments from the HL7 V2.6 messages being parsed. A good resources is Health Level Seven® Standard Version 2.6 -
An Application Protocol for Electronic Data Exchange
in Healthcare Environments at vico.org. Messages have specific structures they are supported by. For example ADT^A08
and ADT^A04
use the ADT_A01
structure to map groups and segments within groups.
Find the associated FHIR resource that maps from the fields in the HL7 Segment. A good example is src/main/resources/hl7/resource/Patient.yml which maps for the PID
segment. TEMPLATING explains how the templates work for mappings.
Reuse existing resources other resources from from src/main/resources/hl7/resource, src/main/resources/hl7/secondary, and data types from src/main/resources/hl7/datatype when possible. Only create new templates if needed.
Modify an existing test in src/test/java/io/github/linuxforhealth/hl7/segments to test details of fields. As an example, see Hl7FinancialInsuranceTest.java. Copy and create a new segment test if needed. Test cases are vital to help check new function, and also ensure that an added function does not break when other later function is added.
(See explanation above)
To add new segments to an existing message, find the associated message template. These are all in src/main/resources/hl7/message. A good example is src/main/resources/hl7/message/DFT_P03.yml which processes the DFT_P03 message. TEMPLATING explains how segments map to FHIR resources.
Reuse existing resources other resources from from src/main/resources/hl7/resource, src/main/resources/hl7/secondary, and data types from src/main/resources/hl7/datatype when possible. Only create new templates if needed.
Modify an existing test in src/test/java/io/github/linuxforhealth/hl7/message to test the structure of the message. As an example see Hl7DFTMessageTest.java. Copy and create a new message test if needed.
Add segment field tests to an existing test in src/test/java/io/github/linuxforhealth/hl7/segments if one exists. As an example, see Hl7FinancialInsuranceTest.java. Copy and create a new segment test if needed.
Test cases are vital to help check new function, and also ensure that an added function does not break when other later function is added.
You want to start with a valid HL7 message. Generate or obtain a valid HL7 v2 message/triggering event. The message can be validated using the HAPI libraries packaged with the converter library. The example below demonstrates default HAPI validation within a JUnit5 test case context. It only validates your proposed message, it does not convert the message or test its conversion.
package com.linuxforhealth.example;
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.model.Message;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class HapiValidationTest {
private HapiContext ctx = new DefaultHapiContext();
@Test
void testValidMessage() throws HL7Exception {
String validMsg = "MSH|^~\\&|system1|W|system2|UHN|200105231927||ADT^A01^ADT_A01|22139243|P|2.4\r"
+ "EVN|A01|200105231927\r"
+ "PID||9999999999|2216506||Duck^Donald^^^MR.^MR.||19720227|M|||123 Foo ST.^^TORONTO^ON^M6G 3E6^CA^H~123 Foo ST.^^TORONTO^ON^M6G 3E6^CA^M|1811|(416)111-1111||E^ENGLISH|S|PATIENT DID NOT INDICATE|211004554\r"
+ "PV1|||ZFAST TRACK^WAITING^13|E^EMERGENCY||369^6^13^U EM EMERGENCY DEPARTMENT^ZFAST TRACK WAITING^FT WAIT 13^FTWAIT13^FT WAITING^FTWAIT13|^MOUSE^MICKEY^M^^DR.^MD|||SUR||||||||I|211004554||||||||||||||||||||W|||||200105231927\r"
+ "PV2||F|^R/O APPENDICIAL ABSCESS\r"
+ "IN1|1||001001|OHIP|||||||||||||||^^^^^^M|||||||||||||||||||||||||^^^^^^M";
Message msg = ctx.getGenericParser().parse(validMsg);
Assertions.assertNotNull(msg);
String[] expectedNames = new String[] {"MSH", "EVN", "PID", "PV1", "PV2", "IN1"};
Assertions.assertArrayEquals(expectedNames, msg.getNames());
}
}
The test case relies on the default validation provided by the parse
method. If an error occurs, the parser will raise an exception within the HL7Exception hierarchy.
(See explanation above)
Review the existing FHIR resource templates in src/main/resources/hl7/resource
to determine if the use-case requires a new resource template.
Create a new HL7 Message Mapping template in /src/main/resources/hl7/message
to support the mapping.
Add the new message type to the supported.hl7.messages
property in src/main/resources/config.properties.
If a new FHIR datatype is required, add a yaml file to src/main/resources/datatype.
Implement test cases to validate the HL7 Message to FHIR Resource mapping. Create a new message test class
in src/test/java/io/github/linuxforhealth/hl7/message to test the structure of the message (see Hl7DFTMessageTest.java.
Create a new tests in src/test/java/io/github/linuxforhealth/hl7/segments to test details of fields. See Hl7FinancialInsuranceTest.java.
An good example of End-to-end test cases are found in /src/test/java/io/github/linuxforhealth/MedicationFHIRConverterTest.java .
The learning curve can feel steep for a new developer. Suggestions for "ramping up":
- Download the project
- Set up your environment for Java development. We have contributors using VS Code, Eclipse, and IntelliJ.
- Run command
gradle clean build
. This will confirm your libraries are set up correctly and your development environment is working. (Be prepared that testing step has 500+ tests and may take 10 minutes or more to complete.) - Select a unit test and run it. This will confirm your unit test set up is working. For example, you could try: Hl7FinancialInsuranceTest.java
- Set
localDevEnv = true
ingradle.properties
. This will help you see your changes without doing a full build. - View the json created from the conversion in the test. The easiest way to do this is put a breakpoint immediately after the command
.convert
, which returns json. For most tests this is in a common method:createFHIRBundleFromHL7MessageReturnEntryList
inResourceUtils.java
. - Use the debugger to step through the asserts of the test. View the associated data structures.
- Look at the templates that make your test run.
- Find the message in src/main/resources/hl7/message. e.g. DFT_P03.yml
- Find the segments created by the message in src/test/java/io/github/linuxforhealth/hl7/segments. For example: Coverage.yml and Organization.yml and RelatedPerson.yml.
- Observe how the Segment.Fields, such and IN1.17 map to resources.
- Make a small change to one of the tests. Change the input HL7 and see how the output works. Repeat.