Nouvelle publication

検索

Article
· Juin 30 23m de lecture

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
Connectez-vous ou inscrivez-vous pour continuer
Article
· Juin 30 3m de lecture

Construindo a Interface por Prompting vs Backend InterSystems IRIS: Lovable, Spec First e REST API

Olá, desenvolvedores!

Observando a avalanche de ferramentas para desenvolvedores movidas por IA e baseadas em vibe-coding que vêm surgindo quase todo mês, com recursos cada vez mais interessantes, eu fiquei me perguntando se seria possível aproveitá-las com o InterSystems IRIS. Pelo menos para construir um frontend. E a resposta é: sim! Pelo menos com a abordagem que eu segui.

Aqui está minha receita para construir a interface via prompting conectada ao backend IRIS:

  1. Tenha uma REST API no lado do IRIS, que siga uma especificação Open API (swagger).
  2. Gere a interface com alguma ferramenta de vibe-coding (por exemplo, Lovable) e aponte essa interface para o endpoint da REST API.
  3. Pronto!

Aqui está o resultado do meu próprio exercício — uma interface 100% criada via prompt conectada a uma REST API IRIS, que permite listar, criar, atualizar e excluir registros de uma classe persistente (Open Exchange, código do frontend, vídeo):

Qual é a receita em detalhes?

Como obter a especificação Open API (Swagger) a partir do backend IRIS

Peguei o template com a classe persistente dc.Person, que contém alguns campos simples: Nome, Sobrenome, Empresa, Idade, etc.

Achei que o ChatGPT poderia gerar a especificação Swagger, mas talvez fosse tímido para fazer isso com ObjectScript (embora talvez consiga agora). Então, gerei o DDL da classe pelo terminal do IRIS:

Do $SYSTEM.SQL.Schema.ExportDDL("dc_Sample","*","/home/irisowner/dev/data/ddl.sql")

E passei esse DDL para o ChatGPT junto com o seguinte prompt:

Por favor, crie uma especificação Open API no formato JSON versão 2.0 a partir do seguinte DDL, que permita obter todos os registros e registros individuais, além de criar, atualizar e excluir entradas. Adicione também um endpoint _spec com OperationId GetSpec. Por favor, atribua nomes significativos para todos os operationId dos endpoints. O DDL: CREATE TABLE dc_Sample.Person( %PUBLICROWID, Company VARCHAR(50), DOB DATE, Name VARCHAR(-1), Phone VARCHAR(-1), Title VARCHAR(50) ) GO CREATE INDEX DOBIndex ON dc_Sample.Person(DOB) GO

E funcionou muito bem — aqui está o resultado.

Depois disso, usei a ferramenta de linha de comando %REST para gerar as classes backend.

Em seguida, implementei a lógica da API REST no IRIS usando ObjectScript para os métodos GET, PUT, POST e DELETE. Na maior parte, manualmente 😉, com alguma ajuda do Co-pilot no VSCode.

Testei a REST API manualmente com o swagger-ui e, depois que tudo estava funcionando, fui construir a interface:

A interface foi criada usando a ferramenta Lovable.dev via prompt:

Por favor, crie uma interface moderna e prática a partir da seguinte especificação Open API, que permita listar, criar, atualizar e excluir pessoas { "swagger":"2.0", "info":{ "title":"Person API," "version":"1.0.0" }, ....(passei a especificação completa)

Depois que a interface foi construída e testada (manualmente), pedi para o Lovable direcioná-la para o endpoint da REST API no IRIS. Primeiro localmente via Docker, e depois de alguns testes e correções (também via prompts), o resultado foi publicado.

Algumas observações e lições aprendidas

  • A segurança da REST API no lado do IRIS não é muito clara de início (principalmente por questões relacionadas ao CORS). Por exemplo, precisei adicionar uma classe especial cors.cls e modificar manualmente a especificação do Swagger para que o CORS funcionasse.
  • A documentação Swagger não funciona automaticamente em containers Docker no IRIS, mas isso pode ser resolvido adicionando um endpoint _spec e algumas linhas de código em ObjectScript.
  • A especificação Swagger para IRIS deve ser na versão 2.0, e não na mais recente 3.1.

Fora isso, essa abordagem se mostrou uma forma bastante eficiente para um desenvolvedor backend IRIS construir protótipos de aplicações full-stack completos em muito pouco tempo, mesmo sem conhecimento de frontend.

Compartilhe sua opinião. Qual é a sua experiência com vibe-coding no desenvolvimento com IRIS?

Aqui está o vídeo demonstrativo:

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Question
· Juin 30

Help with setting up SQL ODBC database connection in IRIS container

I'm running the image "containers.intersystems.com/intersystems/irishealth-community:2025.1" as a container on my local Docker desktop.

Now I want to set up an ODBC SQL connection, but I don't know how to do it.

I have tried various ways without success. Like building my own image (see "Dockerfile" description below).

I have also added ODBCINI variable in my docker-compse (see "Docker-compose.yml" description below).

Anyone done this before?

I'd really appreciate some help.

Thanks.

 

Dockerfile
FROM containers.intersystems.com/intersystems/irishealth-community:2025.1
USER root
RUN apt-get update && \
    apt-get install -y unixodbc odbc-postgresql && \
    apt-get clean && rm -rf /var/lib/apt/lists/*
COPY odbc.ini /etc/odbc.ini
COPY odbcinst.ini /etc/odbcinst.ini
USER irisowner

Docker-compose.yml
services:
  iris:
    build: .
    container_name: iris
    ports:
      - "52773:52773"
      - "1972:1972"
    environment:
      - ODBCINI=/etc/odbc.ini
    volumes:
      - ./iris-init:/irisdev/app
      - iris_data:/ISC/durable
      - /c/temp/IRIS-mnt/mgr:/opt/hc/mgr        # For storing namespace data
    networks:
      - irisnet     # Setting this to be in the same docker network as the postgres database I want to connect to.

volumes:
  iris_data:

networks:
  irisnet:
    external: true

Discussion (1)2
Connectez-vous ou inscrivez-vous pour continuer
InterSystems officiel
· Juin 30

InterSystems Cloud Services - Notas de la versión - 27 de junio de 2025

Referencia: Build 2025.1.0.1.24372U.25e14d55


Resumen

Esta versión introduce mejoras significativas en seguridad, capacidades de análisis y experiencia del usuario, junto con importantes mejoras operativas destinadas a reducir el tiempo de inactividad y mejorar la confiabilidad.


Nuevas funciones y mejoras

Categoría Característica / mejora Detalles
Analíticas Adaptive Analytics en Data Fabric Studio InterSystems Data Fabric Studio ahora incluye Adaptive Analytics como una función opcional, ofreciendo capacidades avanzadas de análisis directamente dentro de tu flujo de trabajo.
Seguridad    Gestión de Firewall Mejorada La página de gestión del firewall ahora permite crear reglas explícitas de entrada y salida específicamente para el puerto 22, proporcionando mayor seguridad y control de acceso.
Actualización de Seguridad en APIs Personalizadas Las APIs personalizadas han pasado de utilizar tokens de ID a tokens de acceso, fortaleciendo la seguridad mediante una mejor autenticación.
Aplicación Obligatoria de HTTPS para APIs Personalizadas Las APIs personalizadas ya no admiten HTTP; toda la comunicación ahora se realiza exclusivamente a través de HTTPS, garantizando una transmisión de datos cifrada y segura.
Mejoras Generales de Seguridad

Se han aplicado múltiples mejoras de seguridad, reforzando la seguridad en toda la plataforma.

Experiencia de usuario Anuncios y Widgets de Nuevas Funciones Se han introducido widgets adicionales para comunicar de manera efectiva nuevas funciones, anuncios y actualizaciones importantes directamente en el Portal del Servicio en la Nube.
Operaciones Mejora en el Desempeño del Cambio de Zona Horaria El tiempo de inactividad asociado con la operación de cambio de zona horaria en entornos de producción se ha reducido significativamente, de aproximadamente 2 minutos a unos 15 segundos, minimizando el impacto en las operaciones.

Acciones recomendadas

  • Explorad el Adaptive Analytics dentro de Data Fabric Studio para mejorar las capacidades de toma de decisiones basadas en datos.
  • Revisad la configuración del firewall para aprovechar las nuevas reglas de entrada/salida del puerto 22. La primera implementación que realicéis definirá las reglas. Aseguraos de revisar las reglas de salida.
  • Aseguraos de que las APIs personalizadas utilicen SDKs actualizados que empleen tokens de acceso en lugar de tokens de ID, y confirmad que las configuraciones exclusivas de HTTPS se apliquen correctamente.

Soporte

 

Para obtener asistencia, abrid un caso de soporte a través de iService o directamente desde el Portal de Servicios en la Nube de InterSystems.


Gracias por elegir InterSystems Cloud Services.

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer
Annonce
· Juin 30

Obtenez une certification en tant que professionnel du développement

Vous avez au moins deux ans d'expérience en développement avec la plateforme de données InterSystems IRIS et des connaissances de base en InterSystems ObjectScript ?

Validez votre expertise avec le nouvel examen InterSystems IRIS Development Professional certification, notre premier examen de niveau professionnel !

Badge: InterSystems Certified. InterSystems IRIS Development Professional  

Que couvre l'examen ?

Bonnes pratiques en :

  • Architecture
  • Cycle de développement
  • Récupération de données
  • Code

Pourquoi obtenir une certification ?

👏 Obtenez une reconnaissance officielle de vos compétences et de votre expérience.
🚀 Boostez votre confiance… et votre carrière !

Comme le dit un client certifié InterSystems :

…la certification est une garantie solide que vous possédez l'étendue et la profondeur nécessaires pour opérer efficacement dans ces technologies.

Discussion (0)1
Connectez-vous ou inscrivez-vous pour continuer