FHIR transactions: the Search functionality

FHIR supports transactions by POSTing a bundle of resources to the root of a server. The server processes them separately as if they had been sent as individual requests – except that the entire group of updates either succeeds or fails as a group (which is what a transaction is, after all…)

It’s one of the more complex processing that a server has to do – particularly as it needs to manage references between resources for new and existing resources within the bundle.

But there’s one particular aspect to this, and that is what if you don’t know if the resource already exists on the server?

For example, we’re working on a project to import glucose data from a personal device. Our current thinking is to create a bundle containing a Patient resource, a Device resource and Observation resources for each of the glucose results we want to save. (We’re probably not using the DeviceObservationReport as it doesn’t add anything extra for us in this scenario).

So when the client creates the bundle, what does it use for the Patient ID – and the Device ID for that matter? (The Observations will always be new, so cid: IDs are appropriate for them). We do have an identifier for both, but that’s not the same as the ID – and having to look up the resources before putting them in the bundle kind of defeats the purpose. And if we include the resource anyway with a cid: ID , then the server will always create a new one – not what we want.

The answer to this is a couple of paragraphs in the spec that talks about how a server can manage this. Here it is (it’s in the transaction description):

The application constructing a bundle may not be sure whether a particular resource will already exist at the time that the transaction is executed; this is typically the case with reference resources such as patient and provider. In this case, the bundle should contain a candidate resource with a cid: identifier, and an additional search parameter using an Atom link:

<link href="http://localhost/Patient?[parameters]" rel="search"/>

A search link with a root of http://localhost means to search the local resource store for a match as specified in the parameters (which must conform to the servers capability for searching as specified in its conformance statement). If the search returns no matches, the server process the resource normally. If the search returns one match, the server uses this matching resource instead, and ignores the submitted resource. If more than one resource is found, the transaction SHALL be rejected.

 This means that we can include the identifier of the Patient and the Device in the bundle, and the server will locate the resource if it exists – and create it if it does not.

So here’s a sample of a patient resource in a bundle:

<entry>
    <title>Patient details</title>
    <id>cid:patient@bundle</id>
    <updated>2014-05-28T22:12:21Z</updated>
    <link href="http://localhost/Patient?identifier=PRP1660" rel="search"/>
    <content type="text/xml">
        <Patient xmlns="http://hl7.org/fhir">
            <text>
                <status value="generated"/>
                <div xmlns="http://www.w3.org/1999/xhtml">Joe Bloggs</div>
            </text>
            <identifier>
                <value value="PRP1660"/>
            </identifier>
            <name>
                <text value="Joe Bloggs"/>
            </name>
        </Patient>
    </content>
</entry>

Note the <link> element where we specify that the search parameter is an identifier with the value of PRP1660. (and, of course, we have this identifier in the candidate resource – otherwise it will never work!)

This is incredibly useful! In fact it does raise the issue of whether a server claiming to be able to process transactions in its conformance statement SHALL be able to implement this functionality. I don’t think the spec is clear on this – and probably needs to be.

 

Getting more than one type of Resource back in a FHIR query

I received an interesting question from a colleague at Orion Health today:

We’re looking at the Appointment API for FHIR for some upcoming work (http://fhir.azurewebsites.net/appointment.html).

The location (http://fhir.azurewebsites.net/location.html) of the appointment is a reference link in the API example, and we want to show that information in the list of appointments for the patient. With the current modelling I think that means we’d have one REST API call for the list and then a REST API for each appointment to get the location information. Do you know if there is any provision in FHIR for being able to “inline” the reference information for lists of content to reduce the number of HTTP requests necessary to obtain and present the information?

This is an interesting question, and one that has a number of solutions.

First – what is not: Contained resources. This was actually the subject of my very first post and you can read the details there, but briefly, contained resources are intended for situations where it is not possible to properly identify a resource – which is clearly not the situation here.

We’ll have a look at 4 possibilities (and there may be more):

  • The display property
  • The _include query parameter
  • A compartment
  • A custom service

The display property is the simplest solution. It is intended to identify what is being referenced (in this case a location resource) and is not a copy of the resource contents. The idea is that it should be enough to display in a list or some other display to the user – so would seem a good fit here. The downside is that it is populated by the resource creator, and may not have all the information that the consumer wants to display.

Next up is the _include query parameter. This allows the consumer to request that the server include other resources in the query, based on a query parameter. So the following query would ask that the server include in the response bundle the Location resources that are referenced by the Appointment resources that match the query

GET /Appointment?participant.individual={patientID}&_include=Appointment.location

The third possibility is the patient compartment. This is really a form of ‘syntactic sugar’ that allows queries to be more naturally expressed. So:

GET /Patient/{patientID}/Appointment?_include=Appointment.location

(btw – I’m not completely sure that this will work as the patient is not a single property. I’ll update the post if there are changes)

And finally, it would be possible to create a custom service – though with the options above, this doesn’t seem necessary, and these are really more intended where there is some business or task based logic to perform.

Note that only the first option is a core part of the FHIR spec – the other options depend on the server implementing them.

So there you go!

And if you are interested in the Appointment resource, now would be a good time to go and comment!

Regional Shared Medications with FHIR

Let’s wrap up this ‘mini-series on medications’ by moving up a notch and considering how we could build a regional repository of patient medications, which would be shared amongst all those involved in a patients care. The idea is that the repository is the ‘single source of truth’ for patient medications. Other systems – such as a GP (or Primary/Ambulatory Care system) , or a hospital on admission/discharge – would access that repository (via FHIR interfaces) when viewing/updating medications rather than their own databases (though they would likely synchronize with rather than replace their local data source – at least initially).

The repository could also support Patient and Provider portals, as well as being ideal for mobile devices.

The picture below shows the ‘big picture’ for what I’m talking about (thanks to Orion Health for the picture):

medman

It shows a single repository of data that is intended to be utilized by all providers – and also the patient and their care givers. The repository would contain a number of different types of medication related data, for example:

  • The current list of medications (modelled as a FHIR List)
  • The MedicationPrescription resources referenced by that List
  • Dispensing (MedicationDispense) resources.

There are also a few supporting resources as detailed below. And there are many other clinical resources (eg allergies) that could be added once the infrastructure was in place.

Use cases

We’ll support the following high-level Use Cases:

  • Store dispensing records from a pharmacy. Each time a pharmacy dispenses a medication, they construct a MedicationDispense resource and save it in the repository.
  • Retrieve dispensing data for a patient over a time period. Used by a clinician when reconciling the patients’ medication list.
  • Get the patients’ current list of medications. Used by anyone involved with the patients’ care – including the patient & their care givers – such as a rest home, GP or ED department.
  • Get the history of changes to the List, and previous versions of that list.
  • Update the patients’ current list of medications.

Note that our Use Cases are related to recording medication information only – specifically we are not (yet) including any ordering functionality (though the use of the MedicationPrescription resource will allow us to do so in the future).

Security

All communication with the system will be over an SSL connection. We’ll use oAuth to identify and authenticate the user. To keep things simple, we will assume that any registered user can access the records of any patient (we’ll have an audit record of course). We’d apply more robust privacy and security rules in a real implementation of course – especially around the updating of medication data – but this is a very large topic that we can’t go into here.

It is worth noting that FHIR has security ‘baked in’ to its design – so we can have confidence that we will be able to do this when we need to.

FHIR Interfaces / end points

The following section lists the FHIR interfaces that we will expose.

It’s not always appreciated that a FHIR server doesn’t have to support all resources – and can apply whatever business logic it needs at the interfaces. In fact, we’re only going to support the endpoints that we need to meet the use cases described above (for the moment).

The following section lists the resources and the end points that our solution will need to expose.

Patient

The Patient will need an identity on our server so that we can find them, and reference the other resources to them. We might maintain this ourselves (hard) or just provide a FHIR façade to an existing identity service. The queries we support are all about getting the patient resource, and include:

  • Find Patient (eg GET /Patient?name=eve)
  • Get Patient by identifier (eg GET /Patient?identifier=PRP1660)

Practitioner

The Practitioner resource is similar to the Patient resource – we need it in a number of places, but we don’t want the responsibility of maintaining the register. So, like Patient, we’ll just provide a façade to the appropriate identity service, with the following endpoints:

  • Find Practitioner (eg GET /Practitioner?name=smith)
  • Get Practitioner by identifier (eg GET /Practitioner?identifier=PRP1660)

MedicationDispense

The MedicationDispense resource is going to be useful when we are assembling the patients Medication List. We’ll take in a feed from pharmacies, and then a client can use that as they check that the list is correct (often termed ‘reconciling’ the list) – e.g. does the list include the medications that the patient has been dispensed?

We will assume that the submitting system has looked up the patient ID when they assemble and send the resource (for example they may use the /Patient endpoint described above to do so).

So we have:

  • Submit a dispense resource (POST /MedicationDispense)
  • Get dispense records in the past (say) month (GET / MedicationDispense?patient={patientID}&whenHandedOver < {1 month ago}

Given the volume of dispensing records, we may also want to support batch insertions of MedicationDispense resources as well.

As an aside, both MedicationDispense and MedicationPrescription resources refer to a Medication resource, which holds the details of the actual drug. The medication resource has a code property that identifies the specific drug within the specified drug terminology. For example in New Zealand we have the ULM (Universal List of Medications) – a terminology based on SNOMED – thus the code 44362701000116107 refers to a 100mg tablet of aspirin.

We’re assuming that the client system will be doing any searching/lookup against that terminology, so all we need is the code and the code system. For this reason our MedicationPrescription and MedicationDispense resources will contain the  Medication resource, rather than referencing  separate resource. There are tradeoffs in this decision as discussed in this post, but it does simplify our architecture, and we can easily change later if we need to without any migration cost.

MedicationPrescription

We’re using the MedicationPrescription resource to record the details of each medication the patient is taking, as it contains details like the drug, dosage information, reason for prescription and suchlike. We’ll use the ‘transaction’ based method of updating this resource that we described in the last post, which means that the only endpoint we need is to retrieve the resource based on the resource ID (which we’ll get from the List)– i.e.

  • Get a single MedicationPrescription (GET /MedicationPrescription/{ID})

List

We’ve talked in the last couple of posts about how to use the List resource to record the patients’ medication list, so lets not repeat all that here. The endpoints we’ll need are:

  • Get a patients list of medications (GET /Patient/{patientID}/List?code=10160-0)
  • Update a patients list of medications. This will be a transaction update as described earlier.

To get the history of changes to the List, we will use FHIR’s versioning abilities. First, the history of changes (assuming the listID is the ID of the list):

  • GET  /List/{listID}/_history

This will return a bundle of resources – each being an older version of the list. Once we have the versionID’s, we can perform a vread of the List as follows:

  • GET  /List/{listID}/_history/{versionID}

This will give a client application the ability to display the changes to the List over time.

SecurityEvent

We haven’t talked about SecurityEvent so far. Based on the IHE ATNA profile, the SecurityEvent is used to maintain an audit log of events that are of significance clinically or legally. We will create a new SecurityEvent resource automatically under the following situations:

  • When someone gets the list of medications for a patient
  • When someone updates the list of medications for a patient

The SecurityEvent will then be available so that we can see who has accessed a patients record – and we intend to make this available to the patient as well via a patient portal. The external endpoint will be quite simple:

  • Get a bundle of SecurityEvent resources for a patient over a given time period (GET /SecurityEvent?patientId={patientID}&date > {startDate} & date < {endDate}

 Notes:

We have had to expose a number of interfaces to support this functionality – but the benefits of doing so would justify the expense in providing a single place where medications are recorded for a patient and accessible by anyone who needs to do so (in the interest of the patient). As mentioned above, security & privacy mechanisms will need to be put in place in a real deployment.

It is worth noting that there are significant benefits to this architecture over a more simplistic approach like simply storing a series of documents – especially when it comes to population based analysis and research. It’s much easier to get at the information when stored in this ‘organized’ way than having to troll through millions of documents every time you wanted to find out specific information – such as who had received a specific drug, or how many patients with a Condition of Diabetes have not had an HBA1c performed in the past 6 months.

Version management also makes timeline changes straightforward, and FHIR is, of course, much easier for mobile devices.

However, I’m the first to admit that it represents quite a leap over how information is managed today! Still, one can dream…

And finally, being good FHIR citizens, our conformance resource is attached…

<?xml version="1.0" encoding="utf-8"?>
 <Conformance xmlns="http://hl7.org/fhir">
   <text>
     <status value="generated"/>
     <div xmlns="http://www.w3.org/1999/xhtml">
       <p>This conformance statement supports the Shared Medication repository, and specifies the following endpoints</p>
       <p>Person: Read and Search on name and identifier</p>
       <p>Practitioner: Read and Search on name and identifier</p>
       <p>MedicationDispense. Create, and search on patient,whenHandedOver</p>
       <p>MedicationPrescription. Read. </p>
       <p>List. Create and search on code,patient. Version read.</p>
       <p>SecurityEvent. Search on patient,date</p>
       <p>Transaction interfaces to update the Medication List</p>
     </div>
   </text>

   <identifier value="68D043B5-9ECF-4559-A57A-396E0D452311"/>
   <version value=".1"/>
   <name value="My List Of Medicines (MLOM) Conformance Statement"/>
   <publisher value="Elbonian MOH"/>
   <telecom>
     <system value="email"/>
     <value value="wile@elbonia.govt"/>
   </telecom>
   <description value="The FHIR endpoints required to support a regional Medication repository - My List Of Medicines"/>
   <date value="2012-10-14"/>
   <software>
     <name value="MLOM"/>
     <version value="0.34.76"/>
   </software>
   <fhirVersion value="0.12"/>
   <acceptUnknown value="false"/> <!--   this system does not accepts unknown content in the resources   -->

   <!--   this system can do either xml or json. (Listing both implies full support for either, with interconversion)   -->
   <format value="xml"/>
   <format value="json"/>
   <!-- We only support REST interfaces at this time. This includes transaction to the server root to update the List-->
   <rest>
     <mode value="server"/>

     <!-- SecurityEvent record -->
     <resource>
       <type value="SecurityEvent"/>
       <operation>
         <code value="read"/>
       </operation>
       <searchParam>
         <name value="patient"/>
         <type value="reference"/>
         <documentation value="Lookup by patient."/>
       </searchParam>
       <searchParam>
         <name value="date"/>
         <type value="date"/>
         <documentation value="Lookup by date the event occurred."/>
       </searchParam>
     </resource>

     <!-- MedicationDispense record -->
     <resource>
       <type value="MedicationDispense"/>
       <operation>
         <code value="create"/>
       </operation>
       <operation>
         <code value="read"/>
       </operation>
       <searchParam>
         <name value="patient"/>
         <type value="reference"/>
         <documentation value="Lookup by patient."/>
       </searchParam>
       <searchParam>
         <name value="whenHandedOver"/>
         <type value="date"/>
         <documentation value="Lookup by date the medication was given to the patient."/>
       </searchParam>
     </resource>

     <!-- MedicationPrescription resource. The prescription records are all created through the 'transaction' process so read-only -->
     <resource>
       <type value="MedicationPrescription"/>
       <operation>
         <code value="read"/>
       </operation>
     </resource>

     <!-- List resource. Used to support the List of Medications. -->
     <resource>
       <type value="List"/>
       <operation>
         <code value="create"/>
       </operation>
       <operation>
         <code value="read"/>
       </operation>
       <operation>
         <code value="vread"/>
       </operation>
       <searchParam>
         <name value="patient"/>
         <type value="reference"/>
         <documentation value="Lookup by patient."/>
       </searchParam>
       <searchParam>
         <name value="code"/>
         <type value="token"/>
         <documentation value="Lookup by code - this will be for the MLOM"/>
       </searchParam>
     </resource>

       <!-- The Practitioner resource endpoint -->
       <resource>
         <type value="Practitioner"/>
         <operation>
           <code value="read"/>
         </operation>
         <searchParam>
           <name value="name"/>
           <type value="string"/>
           <documentation value="Lookup by practitioner name. All parts of the name are searched."/>
         </searchParam>
         <searchParam>
           <name value="identifier"/>
           <type value="token"/>
           <documentation value="Lookup by identifier. Both active and inactive practitioners will be returned."/>
         </searchParam>
       </resource>

     <!-- The Patient resource endpoint -->
     <resource>
       <type value="Patient"/>
       <operation>
         <code value="read"/>
       </operation>
       <searchParam>
         <name value="name"/>
         <type value="string"/>
         <documentation value="Lookup by patient name. Only active patients will be returned. All parts of the name are searched."/>
       </searchParam>
       <searchParam>
         <name value="identifier"/>
         <type value="token"/>
         <documentation value="Lookup by identifier. Both active and inactive patients will be returned."/>
       </searchParam>
       <searchParam>
         <name value="birthDate"/>
         <type value="date"/>
         <documentation value="Lookup by patient birts date. Supports the :before and :after modifiers to allow for age ranges"/>
       </searchParam>
     </resource>
   </rest>
 </Conformance>

In the beginning…

Looking back over the past year, I’ve given a number of talks on FHIR. I’ve also been lucky enough to have been sponsored by my employer – Orion Health – to speak at a number of overseas conferences, including CHIMA in China, and HIMSS Asia-Pac in Hong Kong.

In most of these presentations I’ve started by giving an overview of the HL7 Interoperability standards, and where FHIR fits into that family, including why it was developed in the first place. Sounds like a good topic for a blog post!

The first version of HL7 (which was actually  version 2) was developed around 1987 by Ed Hammond in response to a need to share health information within a healthcare enterprise. The name “HL7” stands for ‘Health Level 7’ – where the 7 refers to the 7th layer (applications) of the OSI model.

I asked Ed why the version was 2 and not 1 – he replied that there was a initially a version .5 that was more of a scoping version, and a version 1.0 that was demonstrated at a HIMSS conference. This was more what we would call a DSTU (Draft Standard for Trial Use) today. Version 2.0 was the first version that made it “into the wild”.

The standard become widely used – largely due to it’s relative simplicity, but also because it allowed individual implementers to define ‘extensions’ to the standards in the form of ‘Z-segments’ which allowed them to share data that had not yet been formally defined in the main HL7 standard.

However a number of issues developed over the years.

  • Implementers produced a proliferation of overlapping Z-segments that could only be understood by the the parties that defined them – usually a single sender and recipient.
  • People started using the defined fields within segments for unexpected purposes – for example if their particular implementation did not need to use a particular field for the defined purpose, they ‘re-used’ it for something else.
  • Individual segments got more and more fields added – with any of them optional

This led to the saying the ‘Once you’ve seen one HL7 v2 implementation –  you’ve seen one HL7 v2 implementation!’  Semantic interoperability – being able to communicate ‘meaning’ was really restricted to individual sets of trading partners who would agree in advance what the meaning of these ‘extended’ fields was.

In response to these issues, HL7 started work on version 3 around 1995. Version 3 created a common  ‘Reference Information Model’ and a standardized development process, from which the various HL7 artefacts were derived. It was an ambitious programme (and not without critics) as it attempted to provide a mechanism to share any clinical information without necessarily having to agree in advance what that information was. The first release was in 2005.

However, with the exception of CDA (Clinical Document Architecture), version 3 didn’t really take off. It was used in Canada (Health Infoway) and the UK (Connecting for health), but most people continued to use v2 for messaging needs, and CDA for documents (in fact – people started using CDA where a messaging approach was really required – as a document standard, CDA does not support workflow). There were a number of reasons for this.

  • Using v3 properly is hard. It is a very abstract standard, and you need to understand quite a bit about it to work with and extend the standard.
  • Development of new business  ‘domains’ was slow – 3-7 years to become ‘normative’ was not unusual.
  • All of the tooling to develop and publish standards needed to be custom built.
  • It has been said that v3 is designed to suit the needs of the modeller, not the implementer. For example, with the exception of CDA, there is no standardized XML schema across all v3 messages.
  • In most cases v2 continued to do the job – why change?
  • The world had moved on – real-time connectivity and the standards that support that (HTTP, XML, JSON, REST, ATOM and many others) were commonplace, as was the concept of “API’s” to support the electronic exchange of information.

Recognizing these issues, the HL7 Board commissioned a ‘fresh look’ at HL7 in 2011. The mandate was ‘What would we do if we were starting with healthcare interoperability from scratch today’? The team noted that:

  • HL7 doesn’t really have a ‘modern’ standard for, say, mobile application or cloud developers.
  • There was a lot of good work and thinking in v3 – it was just hard to get at it.
  • V2 remains enormously popular, yet is based on old technology (but it is simple to understand, and does support extensibility). A migration path is needed.
  • CDA is popular because it supports implementers:
    • There is a standard XML schema – that common tools can manipulate
    • It supports ‘incremental semantic interoperability’ through human readible text elements
    • There is a concise specification, a number of well defined Implementation guides with reference implementations and schematron validators
    • There were many implementations of CDA (and CCD – which is a type of CDA) internationally, and a body of knowledge that built up around it.
    • You don’t need to understand v3 to use it!
    • but – it does not support workflow, and it is designed for the Document paradigm.

Grahame Grieve (from Australia) had already been talking about a different approach – Resources For Healthcare – on his blog (health Intersections) and this was used as the basis to develop what was to become FHIR (Fast Health Interoperability Resources). It was presented at the May Working Group meeting in Vancouver, and quite literally was the star of the show. FHIR had arrived!