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.

Table 3.1: Mapping of data model of Chain of Trust app into FHIR Resources (v4).
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(
  JSON_OBJECT('resourceType', 'Patient'),
  JSON_OBJECT('identifier',
    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
  ),
  JSON_OBJECT('active',
    if(p.active = 0, cast(FALSE as json), cast(TRUE as json))
  ),
  JSON_OBJECT('name',
    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
      )
    )
  ),
  JSON_OBJECT('telecom',
    CASE
      WHEN p.phoneNumber is not null THEN
        JSON_ARRAY(JSON_OBJECT('system', 'phone', 'value', p.phoneNumber, 'rank', 1))
      WHEN p.alternatePhoneNumber is not null THEN
        JSON_ARRAY(JSON_OBJECT('system', 'phone', 'value', p.phoneNumber, 'rank', 1))
    END
  ),
  JSON_OBJECT('gender', 'female'),
  JSON_OBJECT('birthDate', p.dateOfBirth),
  JSON_OBJECT('contact',
    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
  PATIENTS AS p
  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 nesting JSON_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. Using JSON_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 insurancenumber

  • Expected Delivery Data in Observation(Pregnancy)

  • expectedDeliveryDate contains most recent date entered; EDDold contains previously recorded EDD

  • As of summer 2022, loc_id of the sub-village is recorded

  • Sometimes 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 as pnc

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.


  1. OpenHIE Interoperability Layer - Use Cases and Requirements.↩︎

  2. OpenHIM documantation Mediators.↩︎

  3. SQL-on-FHIR working group.↩︎

  4. fhir.resources.↩︎

  5. see this discussion on technical details of handling missing values in FHIR.↩︎

  6. https://github.com/PharmAccess/datacare-fhir-transformation-container↩︎