Skip to main content
Previous sectionNext section

FHIR Data

The following sections explore how to work with FHIR data in InterSystems products.

Accessing FHIR Payloads

The process of accessing FHIR payloads varies depending on the message class carrying the payload. The messages classes for a FHIR production are different than the message classes of a default implementation that does not use a production, therefore accessing the FHIR payload of requests and responses varies depending on the implementation. In both case, manipulating the FHIR data consists of working with dynamic objects.

Implementations Without a Production

By default, when a FHIR request is received by the REST handler, it stores the FHIR payload in the Json property of a Request object (HS.FHIRServer.API.Data.Request), which automatically puts the JSON structure into a dynamic object. FHIR requests that contain XML are converted to JSON before being represented as a dynamic object in the Json property. Responses from the FHIR server (HS.FHIRServer.API.Data.Response) also contain a Json property for FHIR data.

Working with FHIR data begins by getting access to the Json property of the request or response. For example, the following code demonstrates how an ObjectScript application can retrieve a Patient resource from the FHIR server and store it in a patient variable so it can be manipulated as a dynamic object.

set url = "/fhirapp/namespace/fhir/r4"
set fhirService = ##class(HS.FHIRServer.Service).EnsureInstance(url)
set request = ##class(HS.FHIRServer.API.Data.Request).%New()
set request.RequestPath = "/Patient/1"
set request.RequestMethod = "GET"
do fhirService.DispatchRequest(request, .response)
set myPatient = response.Json
Copy code to clipboard

For more information about storing requests and retrieving responses programmatically, see ObjectScript Applications.

Production-Based Implementations

When a FHIR implementation is using an interoperability production, you access the FHIR payload of the message object differently than implementations where a production is not used. In production-based implementations, the request and response messages (HS.FHIRServer.Interop.Request and HS.FHIRServer.Interop.Response) contain a QuickStreamId that is used to access a QuickStream object containing the FHIR payload. Though an interoperability request message also contains a Request property of type HS.FHIRServer.API.Data.Request, this Request property cannot be used to access the FHIR payload because its Json property is transient (the same is true for interoperability responses). As a result, a business process in the production that needs to access the FHIR payload must use the QuickStreamID to obtain a JSON string, then convert that into a dynamic object. For example, a BPL business process could use the following code to access and modify the FHIR payload of a request message that was in JSON format:

//Identify payload as a Patient resource and convert to dynamic object
if ((request.Request.RequestMethod="POST") & (request.Request.RequestPath="Patient")){
  set stream = ##class(HS.SDA3.QuickStream).%OpenId(request.QuickStreamId)
  set myPatient = ##class(%DynamicObject).%FromJSON(stream)

  // Modify Patient resource
  do myPatient.%Set("active", 0, "boolean")

  //Update payload with modified Patient resource
  do myPatient.%ToJSON(stream)
        do stream.%Save()
}
Copy code to clipboard

Of course, the preceding code sample does not apply to request and response message that have a FHIR payload in XML format.

Direct Calls to Interactions Class

FHIR data can be retrieved from the server’s storage strategy programmatically by calling methods of the Interactions class (HS.FHIRServer.API.Interactions). This data is retrieved as a dynamic object. For more information about these method calls, see Bypassing the Service.

FHIR Data and Dynamic Objects

In InterSystems products, FHIR data is represented in dynamic objects, so working with the data is a combination of knowing how to manipulate dynamic objects and how FHIR resources are represented in JSON.

The following code fragments provide an introduction to working with dynamic objects that contain FHIR data. As you’ll see, you need to be familiar enough with the FHIR specification to know the structure of fields in the JSON representation of a FHIR resource. For complete details on manipulating dynamic objects, see Using JSON.

These code examples assume you have a variable patient that is a dynamic object containing a FHIR Patient resource.

Searching for a Value

The following code searches through identifiers of the Patient resource looking for a particular system using two different approaches. In order to write this code, you would need to be familiar enough with the FHIR specification to know that the JSON structure of a Patient resource contains an identifier that has a system name/value pair.

// Put JSON representation of Patient resource into a dynamic object
set patient = ##class(%DynamicObject).%FromJSON("c:\localdata\myPatient.json")

//Searching for a identifier with a specific system
set mySystem = "urn:oid:1.2.36.146.595.217.0.1"

//Approach 1: Use an Iterator    
if $isobject(patient.identifier) {
  set identifierIterator = patient.identifier.%GetIterator()
  while identifierIterator.%GetNext(, .identifier) {
    if identifier.system = mySystem {
      write "Found identifier: " _ identifier.value,!
    }
  }
}

//Approach 2: Use a 'for' loop
if $isobject(patient.identifier) {
  for i=0:1:patient.identifier.%Size()-1 {
    set identifier = patient.identifier.%Get(i)
    if identifier.system = mySystem {
      write "Found identifier: " _ identifier.value,!
    }
  }
}
Copy code to clipboard
Extracting a Value

The following code fragment extracts the family name from the Patient resource.

if $isobject(patient.name) && (patient.name.%Size() > 0) {
  set myFamilyname = patient.name.%Get(0).family
}
Copy code to clipboard
Modifying a Value

The following code fragment sets the Patient resource’s active field, which is a boolean, to 0.

do patient.%Set("active", 0, "boolean")
Copy code to clipboard
Adding a New JSON Object

When you want to add a new JSON object to an existing dynamic object, you can choose whether to use an ObjectScript syntax or a JSON syntax. For example, the following code adds a new identifier to the patient, using two different approaches that have the same result.

set mySystem = "urn:oid:1.2.36.146.595.217.0.1"
set myValue = "ABCDE"

// Approach 1: Use JSON syntax
if '$isobject(patient.identifier) {
  set patient.identifier = ##class(%DynamicArray).%New()
 }

do patient.identifier.%Push({
  "type": {
    "coding": [
      {
        "system": "http://terminology.hl7.org/CodeSystem/v2-0203",
        "code": "MR"
      }
    ]
  },
  "system": (mySystem),
  "value": (myValue)
})

//Approach 2: Use ObjectScript syntax
set identifier = ##class(%DynamicObject).%New()
        
set typeCode = ##class(%DynamicObject).%New()
set typeCode.system = "http://terminology.hl7.org/CodeSystem/v2-0203"
set typeCode.code = "MR"
        
set identifier.type = ##class(%DynamicObject).%New()
set identifier.type.coding = ##class(%DynamicArray).%New() 
do identifier.type.coding.%Push(typeCode)
set identifier.system = mySystem
set identifier.value = myValue
        
if '$isobject(patient.identifier) {
  set patient.identifier = ##class(%DynamicArray).%New()
 }
 do patient.identifier.%Push(identifier)
Copy code to clipboard

Data Load Utility

The Data Load utility sends resources and bundles that are stored in a local system directory directly to the FHIR server with or without going over HTTP. The local FHIR data fed into the Data Load utility can be individual resources, bundles, or both, and can be expressed in JSON, XML, or both. A common use of this utility is feeding large amounts of synthetic data from open source patient generators into the FHIR server.

If getting data to the FHIR server as fast as possible is the objective, it is better to send it directly to the server without using HTTP. In this case, pass the FHIRServer argument to the Data Load utility along with the server’s endpoint. For example, suppose the server’s endpoint is /fhirapp/fhir/r4 and the directory that contains FHIR bundles is c:\localdata. To run the Data Load utility, enter

Set status = ##class(HS.FHIRServer.Tools.DataLoader).SubmitResourceFiles("c:\localdata","FHIRServer","/fhirapp/fhir/r4")
Copy code to clipboard

The utility should print Completed Successfully when it is done processing the files. If it does not, you can print any errors by entering Do $SYSTEM.Status.DisplayError(status).

Alternatively, you can send all the bulk data over HTTP by passing HTTP along with the name of a Service Registry HTTP service. For more information about creating a HTTP service, see Managing the Service Registry. For example, you could run:

Set status = ##class(HS.FHIRServer.Tools.DataLoader).SubmitResourceFiles("c:\localdata","HTTP","MyUniqueServiceName")
Copy code to clipboard

The Data Load utility takes three optional arguments that control whether it displays progress, logs statistics, or limits the number of files in the directory that it will process. For details on these arguments, see HS.FHIRServer.Tools.DataLoader.SubmitResourceFiles()