Article
· 23 hr ago 23m read

FHIR Interoperability in InterSystems IRIS for Health

Overview

Fast Healthcare Interoperability Resources (FHIR) is a standardized framework developed by HL7 International to facilitate the exchange of healthcare data in a flexible, developer-friendly, and modern way. It leverages contemporary web technologies to ensure seamless integration and communication across healthcare systems.

Key FHIR Technologies

  • RESTful APIs for resource interaction
  • JSON and XML for data representation
  • OAuth2 for secure authorization and authentication

FHIR is structured around modular components called resources, each representing specific healthcare concepts, including the following:

  • Patient – Demographics and identifiers
  • Observation – Clinical measurements (e.g., vitals, labs)
  • Encounter – Patient-provider interactions
  • Medication, AllergyIntolerance, Condition, etc.

Resources are individually defined and can reference other resources to form a comprehensive data model.


InterSystems IRIS for Health: FHIR Support

InterSystems IRIS for Health is a unified data platform designed specifically for health care. It includes native HL7 FHIR support. It provides built-in tools and services, enabling storage, retrieval, transformation, and exchange of FHIR resources.IRIS enhances system interoperability with three major FHIR-handling components:

1.FHIR repository Server

IRIS enables rapid deployment of FHIR-compliant servers, with support for the following:

  • The complete FHIR paradigm
  • Implementation of FHIR RESTful APIs, including search and query parameters
  • Importing and utilizing FHIR packages and structure definitions
  • Working with FHIR Profiles
  • Native CRUD operations on FHIR resources
  • Retrieval of FHIR data in JSON or XML formats
  • Support for multiple FHIR versions
  • FHIR SQL builder and bulk FHIR handling capabilities

2. FHIR Facade Layer

The FHIR facade layer is a software architecture pattern used to expose a FHIR-compliant API on top of an existing one (often non-FHIR). It also streamlines the healthcare data system, including an electronic health record (EHR), legacy database, or HL7 v2 message store, without migrating all the data into a FHIR-native system.

This implementation specifically centers around the FHIR Interoperability Adapter.

3. FHIR Interoperability Adapter

InterSystems IRIS for Health offers high flexibility and fine-grained control for transforming such healthcare message standards as HL7 V2.x and C-CDA into FHIR, and vice versa (see the Message Conversion Diagram). However, not all FHIR implementations require a dedicated FHIR repository server. To support such scenarios, IRIS for Health includes an interoperability adapter toolkit that enables detailed message conversion without the need for a FHIR server.

This adapter can handle a variety of external requests (e.g., REST or SOAP APIs) from external systems, transform them into FHIR format, and route them to downstream systems, without necessarily persisting the data to a database.

Alternatively, if needed, the adapter can transform and store the data in the database.

It effectively provides an external interface layer that allows a non-FHIR database to behave as if it were a FHIR server, enabling seamless interoperability.

Message conversion

SDA: Summary Document Architecture

The Summary Document Architecture (SDA) is InterSystems’ intermediary XML-based format used to represent patient data internally within IRIS and HealthShare products. This powerful native data structure enables you to access discrete data and easily convert between multiple data formats, including HL7 V2, CCDA, C32, HL7 FHIR, and others.

 

SDA Structure

The SDA (Structured Data Architecture) is primarily divided into two main components:

  1. Container – Top-level structure containing one or more sections
  2. Sections – Representation of specific healthcare elements(e.g., Patient, Encounter, AllergyIntolerance)

Container

The container is the top level of the SDA standard, and it includes multiple sections (e.g., patient, encounter, allergyIntolerance and others).

Let's explore the internal structure of the SDA and its components.

class definition of Container:

The HS.SDA3.Container class serves as the primary definition for representing an SDA document. Various sections, such as patient and encounter, are defined as objects and included as properties within this class.Sections.

A section is a discrete piece of a container element represented as an IRIS class definition with relevant data elements on the container.

  1. Patient – HS.SDA3.Patient
  2. Encounter – HS.SDA3.Encounter
  3. Allergy - HS.SDA3.Allergy

SDA Container Structure

The below XML structure represents an entire SDA container.

<Container>
    <Patient/>
    <Encounters/>
    <Encounters/>
    <AdvanceDirectives/>
</Container>

 

SDA Data Types

The FHIR data type formats are different from the IRIS standard data types. So, SDA has specific custom data types that handle the properties in sections more effectively than the standard properties, e.g.,  %String, %Integer, %Stream, etc. However, the standard properties are also used in SDA sections.

Those data type classes are also defined inside the HS.SDA3* package:

  • HS.SDA3.Name
  • HS.SDA3.CodeTableDetail.Allergy
  • HS.SDA3.PatientNumber
  • HS.SDA3.TimeStamp

SDA Extension

In most cases, the SDA has sufficient properties to manage and generate all the data coming through the system to develop a resource. However, if you need to accommodate additional data as a part of your implementation, IRIS provides a straightforward way to extend it into the SDA extension classes effortlessly.

For example, HS.Local.SDA3.AllergyExtension class definition is the extension class for the HS.SDA3.Allergy. You can add the necessary data elements to this extension class, simplifying the access and manipulation throughout your implementation.

The next step is to create a container object.


Create a container object

ClassMethod CreateSDAContainer()
{
	
	set SDAContainer = ##class(HS.SDA3.Container).%New()
	
	#; create patient object
	set patientSDA = ##class(HS.SDA3.Patient).%New()
	set patientSDA.Name.FamilyName = "stood"
	set patientSDA.Name.GivenName = "test"
	set patientSDA.Gender.Code="male"
	set patientSDA.Gender.Description="birth gender"
	#; create Encounter 1
	set encounterSDA  = ##class(HS.SDA3.Encounter).%New()
	set encounterSDA.AccountNumber = 12109979
	set encounterSDA.ActionCode ="E"
	set encounterSDA.AdmitReason.Code ="Health Concern"
	set encounterSDA.AdmitReason.Description = "general health concern"
	#; create Encounter 2
	set encounterSDA1  = ##class(HS.SDA3.Encounter).%New()
	set encounterSDA1.AccountNumber = 95856584
	set encounterSDA1.ActionCode ="D"
	set encounterSDA1.AdmitReason.Code ="reegular checkup"
	set encounterSDA1.AdmitReason.Description = "general health ckeckup"
	#; set the patientSDA into the container.
	set SDAContainer.Patient = patientSDA
	
	#; set multiple encounters into the container SDA
	do SDAContainer.Encounters.Insert(encounterSDA)
	do SDAContainer.Encounters.Insert(encounterSDA1)

	#; convert the SDA object into an XML string.
	do SDAContainer.XMLExportToString(.containerString)
	write containerString
}


SDA – XML Document Output

<Container>
	<Patient>
		<Name>
			<FamilyName>stood</FamilyName>
			<GivenName>test</GivenName>
		</Name>
		<Gender>
			<Code>male</Code>
			<Description>birth gender</Description>
		</Gender>
	</Patient>
	<Encounters>
		<Encounter>
			<AccountNumber>12109979</AccountNumber>
			<AdmitReason>
				<Code>Health Concern</Code>
				<Description>general health concern</Description>
			</AdmitReason>
			<ActionCode>E</ActionCode>
		</Encounter>
		<Encounter>
			<AccountNumber>95856584</AccountNumber>
			<AdmitReason>
				<Code>reegular checkup</Code>
				<Description>general health ckeckup</Description>
			</AdmitReason>
			<ActionCode>D</ActionCode>
		</Encounter>
	</Encounters>
	<UpdateECRDemographics>true</UpdateECRDemographics>
</Container>

 In the previous section, we discussed the SDA and its components. We also learned how to generate the SDA via Cache ObjectScript.

Next, we will generate a FHIR resource or Bundle using Interoperability production (formerly known as Ensemble).

Let’s briefly read about interoperability production before creating a FHIR resource.

Interoperability Production with FHIR Adaptor

An interoperability production is an integration framework for connecting systems and developing applications for interoperability with ease. It is typically divided into 3 major components:

  1. Business service – It connects to the external system and receives the request from it.
  2. Business process – It receives a request from the other business hosts, processes the request based on your defined business logic, and converts the relevant data. Multiple components are used to convert the data:
    1. BPL – Business Process Language
    2. DTL – Data Transformation Language
    3. BR – Business Rules
    4. Record Mapping
  3. Business operation – It connects with the external system and sends the response to it.

 

Let’s begin the process of constructing a FHIR message.

Create FHIR Resource

There are two types of systems: FHIR servers and non-FHIR servers. In our case, we aim to make a non-FHIR InterSystems IRIS database appear as a FHIR-compliant system by generating FHIR resources using the FHIR Interoperability Adapters.

In this section, we will demonstrate how to generate FHIR resources from custom data stored in the IRIS database with the help of the InterSystems IRIS for Health Interoperability Toolkit with FHIR adapters.

As a part of this implementation, we will create the following types of FHIR resources:

  1. Standard FHIR Resource – It utilizes the built-in FHIR classes with minimal or no modifications.
  2. Custom FHIR Resource – It involves adding extensions to the SDA model and creating a custom Data Transformation (DTL) for the FHIR resource.

Each implementation will be initiated through dedicated business hosts.

Business Service

The RESTful business host is responsible for receiving requests from external systems. You may configure the appropriate adapter based on your specific integration requirements (e.g., HTTP, SOAP, or other supported protocols). 

Upon receiving a request from the external system, the workflow will generate a corresponding FHIR resource using data persisted in the custom or legacy database.

FHIR Business Process

The FHIR message generation process involves two primary steps:

  1. Transform custom/proprietary data into SDA (HL7 version 2.X to SDA, and CCDA to SDA, etc.).
  2. Add data elements to the SDA and, if required, create a custom DTL. These steps are optional and depend on specific implementation needs, e.g., custom FHIR resource generation.
  3. Then, convert the generated SDA into a FHIR Resource with the help of the IRIS built-in process.

The Structured Data Architecture (SDA) format serves as an intermediary, enabling flexible data transformation. Once the data is available in SDA format, it can be easily mapped to FHIR or other healthcare data standards.

Converting Custom/proprietary Data to SDA Format
In this approach, begin by creating a persistent or interoperability request class to facilitate the transformation into SDA. It involves defining a custom patient class that maps data from your legacy or custom database structure into SDA-compliant objects.

Utilizing a custom patient class provides significant flexibility:

  • It simplifies object handling and manipulation.
  • It enables clean mapping in Data Transformation Language (DTL).
  • It allows an effortless reuse of the object in other transformation or business logic layers.

Request a class for the external layer to convert SDA:

Class Samples.FHIRAdapt.CustomStorage.Patient Extends (Ens.Request,%JSON.Adaptor)
{
Property Name As %String;
Property BirthDate As %String;
Property Citizenship As %String;
Property Religion As %String;
Property PrimaryLanguage As %String;
Property Married As %String;
Property MRN As %String;
}

 

This request class serves as the external interface layer, initiating the conversion process from your database format into SDA. Once the SDA object is created, it can be seamlessly transformed into the desired FHIR resource via standard or custom DTL mappings:

  1. Add the Samples.FHIRAdapt.CustomStorage.Patient (use your class definition) class as the source class for the transformation.
  2. Identify and select the appropriate SDA target class for mapping. In this case, HS.SDA3.Patient is a suitable class for transforming custom data into the SDA format.

Sample DTL conversion

Class Samples.FHIRAdapt.DTL.CustomDataToPatientSDA Extends Ens.DataTransformDTL [ DependsOn = (Samples.FHIRAdapt.CustomStorage.Patient, HS.SDA3.Patient) ]
{

Parameter IGNOREMISSINGSOURCE = 1;
Parameter REPORTERRORS = 1;
Parameter TREATEMPTYREPEATINGFIELDASNULL = 0;
XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='Samples.FHIRAdapt.CustomStorage.Patient' targetClass='HS.SDA3.Patient' create='new' language='objectscript' >
<assign value='$Piece(source.Name,",")' property='target.Name.GivenName' action='set' />
<assign value='$Piece(source.Name,",")' property='target.Name.FamilyName' action='set' />
<assign value='$Piece($Piece(source.Name,",",2)," ",2)' property='target.Name.MiddleName' action='set' />
<assign value='source.Citizenship' property='target.Citizenship' action='set' />
<assign value='"fullname"' property='target.Name.Type' action='set' />
<assign value='$Select(source.Married=1:"married",1:"single")' property='target.MaritalStatus.Code' action='set' />
</transform>
}

}

At this stage, the data has been successfully transformed into an SDA document and is ready for conversion into a FHIR resource.

Before generating the FHIR resource, additional supporting FHIR resources should be created as a part of this response. Besides, the custom fields need to be included in the FHIR output. To support these custom elements, the corresponding properties must be incorporated into the SDA structure.

It can be accomplished with the help of the SDA extensions, which enable the inclusion of custom data elements required for accurate and complete FHIR resource generation.

SDA Extension

FHIR follows the 80/20 rule, where the core FHIR specification covers approximately 80% of common healthcare use cases, while the remaining 20% are addressed through custom constraints and extensions.

To illustrate this, we will create an AllergyIntolerance resource with custom extensions.

There are two key steps for the proper implementation of extension data elements in InterSystems IRIS:

  1. The class HS.SDA3.*******Extension is used to add extra data elements to each SDA section. For example, the class HS.Local.SDA3.AllergyExtension extends HS.SDA3.Allergy by defining the required custom properties.
  2. Since the pre-built DTL mappings do not include these custom extensions, you must create a custom DTL to handle the transformation accordingly.

Allergy Extension Class

To build the required fields in the HS.Local.SDA3.AllergyExtension class for creating the required allergy resource, use the following lines of code:

Class HS.Local.SDA3.AllergyExtension Extends HS.SDA3.DataType
{

Parameter STREAMLETCLASS = "HS.SDA3.Streamlet.Allergy";
/// Mapped this property due to not being available in the SDA to FHIR conversion
Property Criticality As %String;
/// Mapped this property due to not being available in the SDA to FHIR conversion
Property Type As %String(MAXLEN = "");
Storage Default
{
<Data name="AllergyExtensionState">
<Subscript>"AllergyExtension"</Subscript>
<Value name="1">
<Value>Criticality</Value>
</Value>
<Value name="2">
<Value>Type</Value>
</Value>
</Data>
<State>AllergyExtensionState</State>
<Type>%Storage.Serial</Type>
}

}

Making an extension is a halfway done process because standard DTL does not have a mapping for the extension field. Now, we have to construct a custom DTL to transform the FHIR response properly.


Custom DTL Creation

Before customizing DTL classes, you need to define a dedicated package for all of your custom DTL implementations. To do that, InterSystems recommends using the package called HS.Local.FHIR.DTL.

To build a custom DTL for Allergy, start with the existing data transformation class:
HS.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance, which handles the conversion from SDA to FHIR resources.

First, make a copy of this class into your custom package as

HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance. Then, extend it by mapping your custom extensions into the FHIR resource generation process.

For instance, the sample class HS.Local.FHIR.DTL.FromSDA.Allergy demonstrates how to map Allergy extension fields for convenience, while inheriting all other mappings from the base class HS.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance.

Sample custom DTL mapping is illustrated below:

/// Transforms SDA3 HS.SDA3.Allergy to vR4 AllergyIntolerance
Class HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance Extends Ens.DataTransformDTL [ DependsOn = (HS.SDA3.Allergy, HS.FHIR.DTL.vR4.Model.Resource.AllergyIntolerance), ProcedureBlock ]
{

XData DTL [ XMLNamespace = "http://www.intersystems.com/dtl" ]
{
<transform sourceClass='HS.SDA3.Allergy' targetClass='HS.FHIR.DTL.vR4.Model.Resource.AllergyIntolerance' create='existing' language='objectscript' >
<assign value='source.Extension.Criticality' property='target.criticality' action='set' />
<assign value='source.Extension.Type' property='target.type' action='set' >
<annotation>11/07/2023; ak; Added this set to populate type in AllergyIntolerance resource</annotation>
</assign>
</transform>
}

}

Once you have created your class package for custom DTL (in case the custom DTL package does not already exist), you must register it for future FHIR data transformation results.

set status = ##class(HS.FHIR.DTL.Util.API.ExecDefinition).SetCustomDTLPackage("HS.Local.FHIR.DTL")

 Furthermore, you can obtain the custom DTL package details (if already defined) by calling the class method.

Write ##class(HS.FHIR.DTL.Util.API.ExecDefinition).GetCustomDTLPackage()


Stream Container Class for Request Message

The setup of the SDA and its optional SDA extension, along with the optional creation of a custom DTL for building the SDA, is now complete. However, the SDA object must now be converted into a standardized Ens.StreamContainer, used specifically in the SDA-to-FHIR conversion business process.

Here are the simple steps to convert the SDA object to Ens.StreamContainer.

ClassMethod CreateEnsStreamContainer()
{
	set ensStreamCntr=""
	try {
        #; refer the CreateSDAContainer() method above
		#dim SDAContainer As HS.SDA3.Container = ..CreateSDAContainer()
		do SDAContainer.XMLExportToStream(.stream)
		#; Create Ens.StreamContainer is the default format for processing the SDA to FHIR process
		Set ensStreamCntr = ##class(Ens.StreamContainer).%New(stream)
	}
	catch ex {
		Write ex.DisplayString()
		set ensStreamCntr=""
	}
	return ensStreamCntr
}

 The first phase of SDA creation is concluded. The second phase, generating the FHIR resource, is already handled by InterSystems IRIS.

The following article will demonstrate how to convert an SDA document into a FHIR resource.


SDA to FHIR Transformation

Configure Interoperability Business Hosts for FHIR Creation

Business logic for FHIR generation is finalized. Now, let’s configure the Interoperability production setup:

  1. Set up your inbound service to receive requests from the external system.
  2. Business process - it is a crucial step to create the FHIR resource.

Business  Process Implementation

This business process focuses on SDA to FHIR transformation. InterSystems IRIS includes a comprehensive built-in business process, S.FHIR.DTL.Util.HC.SDA3.FHIR.Process that facilitates the transformation of the SDA to the FHIR message. By sending the generated SDA document to this business process, you receive a FHIR resource as a JSON response.

The Process supports two types of FHIR responses based on the SDA input.

  1. Bundle – when an entire SDA container object is sent as an Ens.StreamConainter, the process returns a FHIR bundle with all resources.
  2. Resource - when an individual SDA section (e.g., patient, encounter, allergy) is sent as an Ens.StreamConainter, it returns the corresponding single FHIR resource as a bundle.

Business Operation

The FHIR Bundle is now ready to be returned to the requester or sent to an external system.

Production settings:


Business Service Class

The business service class handles incoming requests from the external system to generate the FHIR.

  1. Upon receiving the request, it creates the SDA using existing logic.
  2. The SDA is then converted into a stream object.
  3. This stream is transformed into the format expected by the standard business process.
  4. Finally, the processed input is sent to the Business Process.
Class Samples.Interop.BS.GenerateFHIRService Extends Ens.BusinessService
{

Parameter ADAPTER = "Ens.InboundAdapter";
Property TargetConfigName As Ens.DataType.ConfigName [ InitialExpression = "HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process" ];
Method OnProcessInput(pInput As %RegisteredObject, Output pOutput As %RegisteredObject) As %Status
{
	#; create your SDA container object and export to stream
	do ..CreateSDAContainer().XMLExportToStream(.sdaStream)
	
	#; convert to the standard Ens.StreamContainer message format
	set ensStreamCtnr = ##class(Ens.StreamContainer).%New(sdaStream)
	
	#; send to the Business process
	do ..SendRequestSync(..TargetConfigName,ensStreamCtnr,.pOutput)
	Quit $$$OK
}

ClassMethod CreateSDAContainer() As HS.SDA3.Container
{
	
	set SDAContainer = ##class(HS.SDA3.Container).%New()
	
	#; create patient object
	set patientSDA = ##class(HS.SDA3.Patient).%New()
	set patientSDA.Name.FamilyName = "stood"
	set patientSDA.Name.GivenName = "test"
	set patientSDA.Gender.Code="male"
	set patientSDA.Gender.Description="birth gender"
	#; create Encounter 1
	set encounterSDA  = ##class(HS.SDA3.Encounter).%New()
	set encounterSDA.AccountNumber = 12109979
	set encounterSDA.ActionCode ="E"
	set encounterSDA.AdmitReason.Code ="Health Concern"
	set encounterSDA.AdmitReason.Description = "general health concern"
	#; set the patientSDA into the container.
	set SDAContainer.Patient = patientSDA
	
	#; set encounters into the container SDA
	do SDAContainer.Encounters.Insert(encounterSDA)
	return SDAContainer
}
}


Creating SDA to FHIR Using ObjectScript

In the previous example, the FHIR resource was generated from SDA with the help of the Interoperability framework. In this section, we will build a FHIR bundle directly utilizing ObjectScript.


Creating a FHIR Bundle from an SDA Container

The CreateSDAContainer method returns an object of type HS.SDA3.Container (we referred to it above). This SDA container must be converted to a stream before being passed to the TransformStream method. The TransformStream method then processes the stream and returns a FHIR bundle as a %DynamicObject in tTransformObj.bundle.

ClassMethod CreateBundle(fhirVersion As %String = "R4") As %DynamicObject
{
	try {	
		Set SDAContainer = ..CreateSDAContainer()
		Do SDAContainer.XMLExportToStream(.stream)
		#; Should pass stream, not a container object
		Set tTransformObj = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformStream( stream, "HS.SDA3.Container", fhirVersion)
		return tTransformObj.bundle
	}
	catch ex {
		write ex.DisplayString()
	}
	return ""
}


Creating a FHIR Bundle Using an SDA Section

In this approach, the patientSDA is declared directly within ObjectScript. This SDA object is then passed to the TransformObject method, which processes it and returns a FHIR bundle as a %DynamicObject.

ClassMethod CreatePatientResourceDirectSet()
{
	try {
		#; convert you're custom dataset into SDA by your DTL
		set patientSDA = ##class(HS.SDA3.Patient).%New()
		set patientSDA.Name.FamilyName = "stood"
		set patientSDA.Name.GivenName = "test"
		set patientSDA.Gender.Code="male"
		set patientSDA.Gender.Description="birth gender"
		#dim tTransformObj As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformObject(patientSDA,"R4")
		set patinetBundle = tTransformObj.bundle
	}
	catch ex {
		write ex.DisplayString()
	}
	return patinetBundle
}

Creating an Allergy Resource with a Custom FHIR DTL and Allergy Extension

  1. Populate all required fields, including custom extension fields, directly within the SDA object.
  2. You should mention the FHIR version type as a second parameter in the TransformObject method (“R4” stands for Resource4 FHIR message).
  3. Pass the completed SDA object to the FHIR transformation class to generate the AllergyIntolerance FHIR bundle.

Note: The custom extension for the allergy resource has already been defined, and the custom DTL mapping has been registered.

ClassMethod CreateAllergyWithDTL()
{
	#; I already registered the "HS.Local.FHIR.DTL.SDA3.vR4.Allergy.AllergyIntolerance" for extension mapping
	#; fetch the data from the table/global and set it into AllergySDA directly.	
	set allerySDA = ##class(HS.SDA3.Allergy).%New()
	set allerySDA.Extension.Criticality = "critial"
	set allerySDA.Extension.Type = "t1"
	set allerySDA.Comments = "testing allergies"
	set allerySDA.AllergyCategory.Code="food"
	set allerySDA.AllergyCategory.Description="sea food"
	#; Set the required and additional properties in SDA, depending on your requirements.
	#; create a FHIR resource from the allergySDA with extension fields that uses a custom "HS.Local.FHIR.*" DTL
	#dim tTransformObj As HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR = ##class(HS.FHIR.DTL.Util.API.Transform.SDA3ToFHIR).TransformObject(allerySDA,"R4")
	Set patinetBundle = tTransformObj.bundle
}

FHIR to SDA Conversion

Custom data, HL7 v2.x, or CCDA messages were previously converted into FHIR. The next implementation involves converting the FHIR Bundle or resource into SDA format, which can then be stored in the database or transformed into CCDA or HL7 v2.x formats.

A JSON or XML-formatted FHIR resource is received from an external system. Upon receipt, the resource must be converted into the internal data structure and stored in the IRIS database.

Business Service

Requests can be received via HTTP/REST or any other inbound adapters based on the requirements.


Business Process - FHIR To SDA Transformation

Once InterSystems IRIS receives the FHIR request message, it provides an extensive built-in business process (HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process). This business process takes a FHIR resource or Bundle as input. The FHIR input can only be of the configured FHIR version. This business process transforms the FHIR data into SDA3, forwards the SDA3 stream to a specified business host, receives the response from the business host, and returns a FHIR response.

Please note that you cannot send the received request to this Business process directly.

The request input type should be in the following:

  1. “HS.FHIRServer.Interop.Request” – for Interoperability production.
  2. “HS.Message.FHIR.Request” – FHIR repository server.

It means that you must convert the request to one of the abovementioned formats before sending.

Creating Interop.Request

ClassMethod CreateReqObjForFHIRToSDA(pFHIRResource As %DynamicObject) As HS.FHIRServer.Interop.Request
{
             #; sample message 
	set pFHIRResource = {"resourceType":"Patient","name":[{"use":"official","family":"ashok te","given":["Sidharth"]}],"gender":"male","birthDate":"1997-09-08","telecom":[{"system":"phone","value":"1234566890","use":"mobile"},{"system":"email","value":"tornado1212@gmail.com"}],"address":[{"line":["Some street"],"city":"Manipal1","state":"Karnataka1","postalCode":"1234561"}]}

	set stream = ##class(%Stream.GlobalCharacter).%New()
	do stream.Write(pFHIRResource.%ToJSON())
	#; create Quick stream 
	set inputQuickStream = ##class(HS.SDA3.QuickStream).%New()
	set inputQuickStreamId = inputQuickStream.%Id()
	$$$ThrowOnError( inputQuickStream.CopyFrom(stream) ) 
		
	#dim ensRequest as HS.FHIRServer.Interop.Request = ##class(HS.FHIRServer.Interop.Request).%New()
	
	set ensRequest.QuickStreamId = inputQuickStreamId
	
	return ensRequest

Once the HS.FHIRServer.Interop.Request message is created, send it to the Business process to convert the FHIR resource to an SDA bundle.

Production settings:


Business Service Class

The Class receives the stream of a FHIR resource via an HTTP request, converts this stream input to the standard process expected format HS.FHIRServer.Interop.Request, and finally calls the FHIR adapter process class to generate the SDA.

Class Samples.Interop.BS.FHIRReceiver Extends Ens.BusinessService
{

Parameter ADAPTER = "EnsLib.HTTP.InboundAdapter";
Property TargetConfigName As Ens.DataType.ConfigName [ InitialExpression = "HS.FHIR.DTL.Util.HC.FHIR.SDA3.Process" ];
Method OnProcessInput(pInput As %Stream.Object, Output pOutput As %Stream.Object) As %Status
{
	set inputQuickStream = ##class(HS.SDA3.QuickStream).%New()
	set inputQuickStreamId = inputQuickStream.%Id()
	$$$ThrowOnError( inputQuickStream.CopyFrom(pInput) ) 
		
	#dim ensRequest as HS.FHIRServer.Interop.Request = ##class(HS.FHIRServer.Interop.Request).%New()
	set ensRequest.QuickStreamId = inputQuickStreamId
	
	Do ..SendRequestSync(..TargetConfigName, ensRequest, .pOutput)
	
	Quit $$$OK
}

}


Creating SDA from the FHIR Resource Using ObjectScript

In the previous example, the SDA document was generated from FHIR with the help of the Interoperability framework. In this section, we will employ an SDA from FHIR directly using ObjectScript.

Once you have received the FHIR resource/Bundle as a request into the IRIS, convert the FHIR JSON to an SDA container:

  1. Convert the InterSystems %DynamicObject AKA JSON into %Stream object.
  2. Execute the TransformStream method from the HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 class, which returns the SDA container object as a response.
///Simple, straightforward FHIR JSON resource to SDA conversion
ClassMethod CreateSDAFromFHIRJSON()
{
	try {
		; have to send as a stream, not a %DynamicObject
		set patientStream = ##Class(%Stream.GlobalCharacter).%New()
		do patientStream.Write({"resourceType":"Patient","name":[{"use":"official","family":"ashok te","given":["Sidharth"]}],"gender":"male","birthDate":"1997-09-08","telecom":[{"system":"phone","value":"1234566890","use":"mobile"},{"system":"email","value":"tornado1212@gmail.com"}],"address":[{"line":["Some street"],"city":"Manipal1","state":"Karnataka1","postalCode":"1234561"}]}.%ToJSON())
		#dim SDAObj As HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 = ##class(HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3).TransformStream(patientStream,"R4","JSON")
		set SDAContainer = SDAObj.container
		
		; XML-based SDA output
		write SDAContainer.XMLExport()
	}
	catch ex {
		write ex.DisplayString()
	}
}


FHIR XML to SDA container.

  1. Convert the XML into %Stream object.
  2. Execute the TransformStream method from the HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 class, which returns the SDA container object as a response.
/// Simple, straightforward FHIR XML resource to SDA conversion
ClassMethod CreateSDAFromFHIRXML()
{
	try {
		set patientXML = "<Patient xmlns=""http://hl7.org/fhir""><id value=""example""/><text><status value=""generated""/><div xmlns=""http://www.w3.org/1999/xhtml""><p>John Doe</p></div></text><identifier><use value=""usual""/><type><coding><system value=""http://terminology.hl7.org/CodeSystem/v2-0203""/><code value=""MR""/></coding></type><system value=""http://hospital.smarthealth.org""/><value value=""123456""/></identifier><name><use value=""official""/><family value=""Doe""/><given value=""John""/></name><gender value=""male""/><birthDate value=""1980-01-01""/></Patient>"
		set patientStream = ##Class(%Stream.GlobalCharacter).%New()
		do patientStream.Write(patientXML)
		#dim SDAObj As HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3 = ##class(HS.FHIR.DTL.Util.API.Transform.FHIRToSDA3).TransformStream(patientStream,"R4","XML")
		set SDAContainer = SDAObj.container
		
		; XML-based SDA output
		write SDAContainer.XMLExport()
	}
	catch ex {
		write ex.DisplayString()
	}
}

 By following the steps detailed above, you can seamlessly transform data to or from a FHIR resource.

Other built-in FHIR repository and FHIR Facade options are valuable tools for exposing a FHIR-compliant system and for handling and storing FHIR resources efficiently.

Discussion (0)1
Log in or sign up to continue