3 FHIR mediator
3.1 The Interoperability layer (IOL)
An interoperability layer (IOL) is a system that enables simpler interoperability between disparate information systems. In the context of the health data commons platform we seek to demonstrate here, the IOL aims to connect the Point-of-Service systems, the commons services and business services. As such, the interoperability Layer receives transactions from client systems, coordinates interaction between the different components of the ecosystem and provides common core functionality to simplify the data exchange between systems.
The openHIE framework provides a detailed specification of the interoperatbility layer.1 Within the scope of our demonstrator projects, the following functional requirements are the most relevant:
- Provides a central point of access for the services of the HIE. For example this interface will provide access to the CR, PR, FR and SHR. This central point of access simplifies security management and provides a single entry point into the HIE.
- Provides routing functions that allow messages to be routed to the correct service provider systems within the HIE
- Provides a central logging mechanism for the messages sent through the exchange. This function should log copies of the messages that travel through the interoperability layer for audit and reporting purposes.
- Adaptor mediators accept a request and transform/adapt that request into another format before sending the request on to its final destination
- Orchestration mediators accept a request and uses that request to execute some business process. This could involve making webservice calls to one or more other services to gather additional information about the request or to process it further. Finally a response is collated and returned to the OpenHIM.
The technical implementatation specification of OpenHIM states that mediators can be built using any platform or programming language, with the only restriction that it interfaces with openHIM via RESTful APIs.2 In the following we demostrate a FHIR adaptor mediator, whereby data from the PoS system (in this case, the CoT app of MomCare Tanzania) can be extracted and stored in the SHR using FHIR version 4. This approach is in fact identical to the storage-less FHIR facade solution pattern described in Section 1.3.3. As the OpenHIM platform provides many of the core functions, such as authentication, routing, logging etc., our demonstrator focuses on mapping and translating a legacy system onto the semantics of FHIR Resources.
3.2 FHIR adaptor for MomCare Tanzania
The main objectives of this demonstrator were to assess the complexity and effort required to implement i) the data transformation scripts, to be used for standardized reporting and secondary analytics (see demonstrators in Chapter 5 and Chapter 9); and ii) the workflow orchestration required for the FHIR adapter. In view of simplicity and speed of development, we have chosen to implement the logic of the mapping in SQL, such that the extraction and mapping of the FHIR Resources could be performed directly on the CoT database (MySQL version 5). This approach is in line with ongoing effort within the FHIR community to support JSON data in modern database engines.3. Since nearly all major database systems support JSON, the approach demonstrated here can be applied to most relational database systems.
The results of the data transformation into 10 FHIR v4 resources is shown in table 3.1, listing the number of records per resource type. The conceptual data model of the existing MomCare app could readily be transformed into the semantics of FHIR Resources using SQL and validated with a FHIR Python library.4 The largest challenge during the transformation process pertained to the absence of unique business identifiers for patients and healthcare organizations. For patients, either the mobile phone number or the healthcare insurance number was taken, depending on availability. A combination of name, address and latitude/longitude coordinates were used to uniquely identify organizations and locations, as Tanzania does not have a system in place for this purpose.
CoT concept | FHIR v4 resource | Business key | # records | |
---|---|---|---|---|
Patient | Patient | patients.id |
28,161 | |
Patient.EDD | Observation(Pregnancy: EDD) | reference to patients.id and effectiveDateTime = patients.updatedOn |
28,587 | |
Clinics | Organization | clinics.id |
70 | |
Clinics.lat/lon | Location | Lat-lon coordinates | 70 | |
Enrollments | EpisodeOfCare | enrollments.id |
20,571 | |
Visit | Encounter | visits.id |
174,998 | |
Diagnoses | Condition | CONCAT(visits.id, diagnoses.id) |
157,162 | |
Asset | Procedure, MedicationAdministration | visit_diagnoses table links clincal findings to Encounters | 1,098,129 | |
Appointment | Appointment | tbd | tbd | |
BaselineSurvey, Survey | Questionnaire | baseline_surveys.id , surveys.id |
4 | |
BaselineAnswers, SurveyResponse, Questions | QuestionnaireResponse | baseline_answers.id , survey_responses.id , questions.id |
tbd |
As an example, the SQL code for extracting the Patient resource is shown below.
SELECT
JSON_MERGE_PATCH('resourceType', 'Patient'),
JSON_OBJECT('identifier',
JSON_OBJECT(CASE WHEN p.mAfyaCardNumber IS NOT NULL AND trim(p.mAfyaCardNumber) <> '' THEN
JSON_ARRAY(
JSON_OBJECT('use', 'temp',
'value', REPLACE(p.ID, ' ', '-') -- FHIR.Patient.identifier.value need to match regex "[ \r\n\t\S]+"
),
JSON_OBJECT('use', 'usual',
'type', JSON_OBJECT(
'coding', JSON_ARRAY(
JSON_OBJECT('system', 'http://terminology.hl7.org/CodeSystem/v2-0203',
'code', 'NIIP',
'display', 'National Insurance Payor Identifier (Payor)'
)
)
),'value', REPLACE(p.mAfyaCardNumber, ' ', '-') -- FHIR.Patient.identifier.value need to match regex "[ \r\n\t\S]+"
-- can't add system because Tanzania National Health Insurance Fund doesn't have URI
)
)ELSE
JSON_ARRAY(
JSON_OBJECT('use', 'temp',
'value', REPLACE(p.ID, ' ', '-') -- FHIR.Patient.identifier.value need to match regex "[ \r\n\t\S]+"
-- can't add system because Tanzania National Health Insurance Fund doesn't have URI
)
)END
),'active',
JSON_OBJECT(if(p.active = 0, cast(FALSE as json), cast(TRUE as json))
),'name',
JSON_OBJECT(
JSON_ARRAY(
JSON_OBJECT('text', CONCAT_WS(' ', TRIM(p.firstName), TRIM(p.lastName)),
'family', TRIM(p.lastName),
'given',
CASE WHEN p.middleName IS NOT NULL AND trim(p.middleName) <> '' THEN
JSON_ARRAY(REPLACE(p.middleName, ' ', '-'), REPLACE(p.lastName, ' ', '-')
)ELSE
JSON_ARRAY(REPLACE(p.lastName, ' ', '-')
)END
)
)
),'telecom',
JSON_OBJECT(CASE
WHEN p.phoneNumber is not null THEN
'system', 'phone', 'value', p.phoneNumber, 'rank', 1))
JSON_ARRAY(JSON_OBJECT(WHEN p.alternatePhoneNumber is not null THEN
'system', 'phone', 'value', p.phoneNumber, 'rank', 1))
JSON_ARRAY(JSON_OBJECT(END
),'gender', 'female'),
JSON_OBJECT('birthDate', p.dateOfBirth),
JSON_OBJECT('contact',
JSON_OBJECT(
JSON_ARRAY(
JSON_OBJECT('organization', JSON_OBJECT(
'reference', CAST(c.id AS CHAR(50)),
'display', CONCAT_WS(', ', c.name, c.locality, c.region),
'type', 'Organization'
)
)
)
)AS patient
)
FROM
AS p
PATIENTS LEFT JOIN CLINICS AS c ON p.clinicId = c.id
WHERE
<> '' p.lastName
While this query may seem verbose, writing such extraction scripts can be done within typically one day provided the developer/data analyst has prior knowledge of the data model of the PoS system. In this example, three JSON functions are used to construct the Patient resource, element by element:
JSON_OBJECT
is used to extract{key: value}
from the relational database. By nestingJSON_OBJECT
function calls, the FHIR resource is constructed element by element;JSON_ARRAY
is used to enable list of values for a given key, for example, multiple names.JSON_MERGE_PATCH
is used to handle missing values: the FHIR specification is quite strict that{key: value}
pairs should only be included if there is in fact a value recorded in the system. UsingJSON_MERGE_PATCH
, all keys that don’t contain a value are discarded.5
Besides the SQL scripts, the mediator is packages in a Docker container such that it can be deployed as a microservice. Specific for MomCare Tanzania the FHIR adaptor was put in production on the Azure cloud platform. More Source code for this demonstrator is available on GitHub.6
3.3 Details per resource
Patient
Insurance number is incomplete, but in theory only insured mothers are treated
User can choose which
externalID
is used: QR-code (patientID), phonenumber or insurancenumberExpected Delivery Data in Observation(Pregnancy)
expectedDeliveryDate
contains most recent date entered;EDDold
contains previously recorded EDDAs of summer 2022,
loc_id
of the sub-village is recordedSometimes patients lose their QR code. If we can’t find/reconstruct this code, a new QR code i.e. patientID is generated
Observation
FHIR International Patient Summary defines specific Observations related to pregnancy:
Clinics
- iProvideID is from PharmAccess database used across different programmes
- lat-lon coordinates are used for uniquely idenfiying clincs, as there are no official codes to identify healthcare providers
Location
- Hierarchy of regional subdivision: country (0) –> region (1) –> district (2) –> division (3) –> ward (4) –> village (5) –> sub-village
- ISO-3166-2:TZ has codes for regions (wiki)
- No official codes exist for divisions and below, so we stick to names
- shapefiles up to ward level (3) are available (link)
- Too many missing values, not used in MVP |
EpisodeOfCare
endDate
taken as expectedDeliveryDate + 20 weeks, which is standard follow-up period
Encounters
- Actual visit of pregnant woman at clinic site |
- As of 2022,
immunization
is added as new encounter type; prior to that, immunizations were registered aspnc
Condition
- visit_assets table contains all procedures performed and/or medication administered
- Mapping internal diagnoses: A1, A2 and A3 are internal codes. These are mapped as follows
- A1 –> Z34, Supervision of normal pregnancy
- A2 –> O80, Single spontaneous delivery
- A3 –> Z39, Postpartum care and examination
Appointments
- Not linked to Encounters
- Not mandatory to fill in nor update status
Referrals
Questionnaire
Questionnaire data is coming from different resources in the COT database. The Baseline survey tables are the result of questionnairs taken via the app. The Survey tables of questionnaires taken via SMS and the questions table TODO.
QuestionnaireResponse
TO DO:
- Assets
isResource
pertains to consumable goods - Referrals are incomplete, records referral to other provider for e.g. abortion
- Users care Caregivers
- Risklevel is derived from risk-scoring model in datawarehouse
3.4 Concluding remarks
We have demonstrated that extracting FHIR Resources from a PoS is viable by directly querying the relational database using JSON functions. This approach can be replicated for other PoS systems and can be integrated into OpenHIM as a mediator.
OpenHIE Interoperability Layer - Use Cases and Requirements.↩︎
SQL-on-FHIR working group.↩︎
see this discussion on technical details of handling missing values in FHIR.↩︎
https://github.com/PharmAccess/datacare-fhir-transformation-container↩︎