Profiling FHIR in DSTU-2

As we mentioned in the previous post, profiles have changed significantly in the next DSTU.

Profiling is a really important part of FHIR. The resource themselves are designed to be quite generic ‘building blocks’ that can be used in many different contexts. If you take a look at one, you’ll notice that almost all of the properties are optional and even where coded properties have Terminologies assigned to them, these are often quite ‘loose’ and designed to be amended by a Profile

Read more of this post

FHIR Profiles: an overview

I’ve been spending a lot of time recently looking at Profiles (we’re building a tool to help manage the ones we’re creating at the moment).

As we start to implement FHIR interfaces in real systems, we’ve come to appreciate just how important profiles are going to be. The reason  is that FHIR is essentially a set of basic building blocks (health-IT lego if you will) and some rules around how to manipulate them. The specification is deliberately very flexible to allow the blocks to be used in lots of different scenarios, both in terms of interoperability paradigms (document, message, REST, service) but also in different countries that can have vastly different requirements in terms of content, terminology, privacy and the like.

Furthermore, and again by very deliberate design, the ‘core’ contents of resources are limited to those elements that are currently being used by most implementers world-wide. This is to keep them manageably sized – the so-called ‘80%’ rule (which, unfortunately, has caused a lot of confusion as my colleague Edward has complained about). From a FHIR perspective there is no difference between core and extension properties – it’s just that the core properties are more common. (Perhaps we should have called extensions ‘special’ elements rather than ‘extensions’…)

What all this means is that in practice when you start to use FHIR for real, you’re likely going to need to adapt the resources to suit your own requirements, and that is where profiles come in.

A sample process might be:

  • Start with a set of requirements (Use cases, user stories, story boards etc).
  • Define the behaviours and the data models you’re going to need. (Behaviours – e.g. queries, workflow, updates, services etc. are outside the scope of this post – but you’d document them in the Conformance resource).
  • Once you have the data model (and these may be in a form like openEHR archetypes – or just a simple table), you then need to map these to the FHIR resources. It’s at this point that you’ll likely find:
    • There are some things you want to exchange that aren’t in the current resources
    • The resources have elements that you don’t want to use.
    • You will want to be more specific about some aspects of the resource – e.g. use a specific terminology for an element, or make an element required rather than optional
    • There might even be models for which no resource can be found. Again this is a bit outside the scope of what we’re talking about here – an option is to use the Other resource (originally known as the resource-with-no-name) and define everything as extensions in a profile.

It’s the profile that allows you to define these differences in a way that the people with whom you are interoperating can understand what you’re trying to say.

So what can you do with a profile? Broadly there are 2 things that you use them for:

  • Adapting the core resource structures to meet your requirements
  • Defining extensions on resources – extra properties needed for your use case.

And there’s a third category – metadata. Metadata is all about describing what the purpose of the profile is (what requirements it fulfils) and discoverability.

  • If we are a server then a client can read our conformance resource, which will list the profiles we support (and provide a link to them).
  • If we are a client, we can tell a server that we conform to a profile (the server will probably still check).
  • If we receive a resource with an extension we don’t recognise, it will point to the profile in which it is described so we can decide what to do with it.

It’s important to appreciate that a single resource instance can have extensions from many different profiles, hosted by many different servers (a profile is just a resource after all – anyone can store them). And also important to appreciate that a profile cannot change the definition of a resource in such a way that it cannot be processed without referring to the Profile – this is the reason behind some of the thing you can’t do with profiles.

And when you design – and use – profiles, you really need to be thinking about re-usability – as Lloyd commented on the previous post, it’s better to have a generic profile/extension that can be used in multiple places than a specific extension that can only be used in one. Or even better, use one that someone else has defined – discoverability of ‘prior art’ is something that we really need to work on, which will be facilitated by the availability of public registries for profiles, and better searching – codes, tags – that sort of thing.

Anyway, on with some more detail on Profiles.

Adapting the core resource structure

Each element in a resource can have a number of characteristics

  • Its name
  • One or more datatypes
  • Multiplicity (how many there can be in a resource)
  • Possibly a binding to a terminology (which may or may not be defined in the spec)

Apart from the element name, the Profile can be used to constrain any of these characteristics – within limits. The following sections describe the most common things you might want to use a profile for.

DataType

You can specify that for your Use Case, the datatype must be a specified sub-set (or just one) of those defined. For example, Observation.subject can be a Patient, Group, Device or a Location, but in your use case, it might only make sense to be a Patient. Note that you cannot specify a datatype that is not already one of the options (or a recipient that didn’t know about your profile wouldn’t know what to do).

Multiplicity

The following table shows how you can alter the multiplicity, with the rows being the multiplicity in the spec and each column being a multiplicity you can specify in the Profile.

0..0
(Not used)
0..1
(optional)
0..n
(optional, many)
1..1
(required)
1..n
(at least 1)
0..1 yes yes no yes no
0..* yes yes yes yes yes
1..1 no no no yes no
1..* no no no yes yes

In summary:

        • If it’s already optional then you can make it required or not used.
        • If it’s already required then you can’t make it optional
        • If more than one is allowed, then you can restrict the number (this is called ‘slicing’ – refer to the spec for details)
        • If only 1 is specified, then you can’t make it many.

The following snippet shows how we’ve restricted the datatype of ‘asNeeded’ in the MedicationPrescription resource to Boolean, and also made it required, by setting both min and max to 1.

<structure>
    <type value="MedicationPrescription"/>
    <name value="asNeededConstraint"/>
    <element>
        <path value="MedicationPrescription.dosageInstruction.asNeeded"/>
        <definition>
            <short value="Only support boolean in the 'asNeeded' property"/>
            <formal value="Only support boolean in the 'asNeeded' property"/>
            <min value="1"/>
            <max value="1"/>
            <type>
                <code value="boolean"></code>
            </type>
            <isModifier value="true"/>
        </definition>
    </element>
</structure>

Terminology

Many of the elements can refer to a code-set, a terminology or a ValueSet. These elements generally have the datatype of coding or codeableConcept. In most cases the spec doesn’t say which terminology to use (though there will often be examples or recommendations). You can use a Profile to specify a terminology or ValueSet you want to use.

(Note that the code datatype is generally bound to a fixed set of values than cannot be altered in a Profile. These are reserved for elements that are generally used in workflow scenarios – ‘status’ elements are the most common).

The following snippet shows how we’ve restricted the code values that can be used for medications to those defined in a ValueSet of ULM (Universal List of Medicines) codes that a GP (Ambulatory care) clinician can prescribe. We could also have used a direct reference rather than the  ValueSet, but the ValueSet allows us to filter the list.

<structure>
    <type value="Medication"/>
    <name value="medicationCodeConstraint"/>
    <element>
        <path value="Medication.code"/>
        <definition>
            <short value="GP ULM Codes only"/>
            <formal value="Specify that the medication code must come from the NZ ULM codeset"/>
            <min value="0"/>
            <max value="1"/>
            <isModifier value="false"/>
            <binding>
                <name value="List of medications GP's can prescribe"/>
                <isExtensible value="false"/>
                <referenceResource>
                    <reference value="http://www.nzgovt/fhir/ValueSet/ulm-gp"/>
                </referenceResource>
            </binding>
        </definition>
    </element>
</structure>

Default Values

You can’t set a default value. The reason for this is that if you could, then it wouldn’t be safe to process a resource without referring to the Profile – which would severely impact on usability.

Extensions

As we’ve discussed previously, we use extensions where we have some data that we wish to exchange that is not currently in the FHIR resource.  We’ve talked about extensions before and made some notes about them when thinking about code sets, so we won’t go over that again but everything that you can do to a structure (core element) you can do with an extension – in fact much of the definition in the profile is the same for both.

Last Word

As I hope you agree, the profile is an important resource to get your head around – and to use. When the public registries become available, re-use of profiles and extensions is going to become a lot easier – but in the mean time you can practise using Grahames  or Ewouts server.

And remember that the enforcing of the constraints described in the profile is completely up to you. FHIR gives you the mechanics to describe these constraints in and easy to use, computable way. It’s up to you to adhere to / validate those constraints.

Profiles and ValueSets in FHIR

I’ve been meaning to talk about Profiles and ValueSets for a little while now. They’ve come up from time to time in this blog – this post was a comment from Grahame about the use of Profiles for specific Use Cases, and we’ve have a number of discussions about extensions such as this one which are defined in profiles.

Profiles are actually a ‘big thing’ for FHIR. You can think of the base FHIR structures (Resources, Extensions, Bundles, Tags, Queries etc.) as the common building blocks that you can use to build a solution – the Profile is where you can say how these blocks are used in your particular application – and what are the extra data items (represented as extensions) that you need.  And this can be both computable and as documentation for humans.

Update: Rene Spronk has commented about a video tutorial given by Ewout Kramer that can be found here. This gives a nice overview of profiles and is well worth a read…

Before we get into too much detail, lets talk about a couple of related resources – Conformance and ValueSet.

Conformance

The Conformance resource is used to describe the capabilities of a particular server. This can either be about an actual server (it can be downloaded by a query to the server root like this: http://fhir.healthintersections.com.au/open/metadata – or using the OPTIONS verb) or it can be used when creating specifications for a server – what a client expects a server to be able to do.

As well as specifying the ‘standard’ resources and queries, the conformance resource can reference the profiles that it supports.

Suppose, for example, that we defined a profile for an antenatal visit. The profile might specify:

  • a particular Questionnaire resource (questionnaire.name / questionnaire.identifier)
  • that the questionnaire author must be a Practitioner
  • that the subject is required and so forth

(we’ll talk about how to do this later). We’ll give this profile an identifier that we’ll call ‘antenatal’ in this post.

A server that supported this profile – i.e. it could check that a particular questionnaire had the right identifier, has a subject and a Practitioner author etc. would then add this profile to its conformance statement – if it receives a questionnaire claiming to conform to the antenatal profile, then the server can check that it does – rejecting it if not (and ideally including an OperationOutcome in its response to say why it failed.) Actually – to be correct the spec doesn’t state that the resource should be rejected – that’s up to the implementation to decide.

Now suppose that we have a client application that can create a questionnaire that conforms to this profile. All it needs to do is to POST the questionnaire to the servers Questionnaire endpoint, including a profile tag HTTP Header in the request that contains the antenatal profile. The server recognizes the tag, loads the profile and checks that the submitted resource does, in fact, meet the requirements of the profile. (Again, the details of this are up to the implementation)

In this way, the server can apply business level validation to resources to ensure compliance with business rules.

Finally, a single server can support multiple profiles (Indeed, a single resource could also be compliant with multiple profiles).

ValueSet

A ValueSet is simply a set of codes. It is used where you want to specify that the value for a particular code in a resource is drawn from a pre-defined set of codes. (It can get quite  a lot more complex than that of course, but that description will do for now)

For example, suppose we are recording medicationAdministrations, and want to be able to indicate whether a particular administration was given on time, was early or was late. MedicationAdministration does not have this property so we create an extension definition (in a profile) to represent it. We actually have 2 steps to do in setting this up.

  • First, we create the ValueSet resource. In this case we’ll define the values directly in the ValueSet (we could also refer terminologies like SNOMED or LOINC if that were appropriate) and give it an appropriate identifier. Here is what it might look like
<ValueSet xmlns="http://hl7.org/fhir">
     <identifier value="onTimeOrNot"/>
     <name value="medsontime"/>
     <description value="Were medications given on time"/>
     <status value="draft"/>
     <!-- Define the  options in the resource rather than an external terminology-->
     <define>
         <system value="http://fhir.orionhealth.com/fhir/ns/onTimeOrNot"/>
         <concept>
             <code value='early'/>
             <display value="Early"/>
             <definition value="The medication was given early"/>
         </concept>
         <concept>
             <code value='on-time'/>
             <display value="Early"/>
             <definition value="The medication was given on time"/>
         </concept>
         <concept>
             <code value='ate'/>
             <display value="Late"/>
             <definition value="The medication was given late"/>
         </concept>
     </define>
 </ValueSet>

  • Next we create a profile with an ID of ‘medadmin’ (so we can easily refer to it in a URL) and in that profile we’ll create an extension definition (ExtensionDef). We’ll give the extension a code of ‘onTimeOrNot’. In the definition of the extension we indicate that the datatype of the extension is a code, and that the value of this code must come from the ValueSet we just created (this is called a binding) – by including a reference to the ValueSet in the extensionDef element. Here’s an example (assuming that the ID of the ValueSet was 100):
<extensionDefn>
     <code value="onTimeOrNot"></code>
     <contextType value="resource"/>
     <context value="MedicationAdministration"/>
     <definition>
         <short value="Was the medication given on time"/>
         <formal value="Was the medication given on time"/>
         <min value="0"/>
         <max value="1"/>
         <type>
             <code value="code"/>
         </type>
         <isModifier value="false"/>
         <binding>
             <name value="Set of coded values"/>
             <isExtensible value="false"/>
             <referenceResource>
                 <reference value= "http://fhir.orionhealth.com/fhir/ValueSet/100"/>
             </referenceResource>
         </binding>
     </definition>
 </extensionDefn>

Both resources get saved on our (or someone else’s) server.

When we want to create a MedicationAdministration resource that can record whether the medication was given on time, we simply include an extension in the resource like so:

<extension>
  <url value = 'http://myserver/profiles/medadmin#onTimeOrNot'/>
  <valueCode value = 'early'/>
</extension>

(If we need to, we can GET the profile, then GET the ValueSet to display a list to the user – though we’ll often have that in our application anyway).

If a recipient receives our resource and doesn’t know what ‘onTimeOrNot’ means, they can follow the url to the Profile which will describe the extension, and to the ValueSet which has the options. Of course, as this was an ‘ordinary’ extension we can safely ignore it if we don’t understand it – had it been a modifierExtension then it wouldn’t have been safe to do so.

The following diagram shows the relationships between these resources and note that they are all ‘instance’ resources with a ID – an fact the Profile & ValueSet resources could form the basis for a registry…

profile-1 (1)

Profile

So we’re now ready to start talking about the Profile – and we’ve pretty much used up the space. Just a summary then, and the next post will go into more detail.

  • The profile is how you ‘constrain’ one or more resources to meet your particular Use Case.
  • It is also where you define the extensions you are going to need (and you almost certainly will need some).
  • You can also define custom queries here
  • It contains both computable artifacts and human documentation.
  • It can get complex! – for example one profile can refer to another

One last thing to point out is what profiles can’t do, and that is to change a resource in such a way that a recipient must understand the profile to safely process the resource. This is an absolute no-no in FHIR. For example, you can’t specify a default in a profile, or require the recipient to download the profile before processing.

If you do need to specify something that must be understood then create an extension setting the ‘isModifier’ to true. A resource instance will use the modifierExtension element to hold this data – and a FHIR recipient must always understand modifierExtensions to safely process resources.

FHIR server exploration tools

Just found this cool tool for exploring a FHIR server. It is hosted by Furore – the guys who also host a public test server, and allows you to view the conformance resource of any publicly accessible server, and then has a simple query builder that assembles a query, and returns all matching resources – displaying the text property.

Grahames test server has a similar facility – in fact allows you to view the resources directly, in XMl & JSON etc – but only operates against his server.

Both are cool tools if you’re starting out…

btw – there are other tools mentioned on the Furore site – a profile editor and a server test tool that you can request from furore…

FHIR Connectathon: The conformance resource for a client

The planning for the 5th FHIR connectathon is underway, with an announcement yesterday on the FHIR list server encouraging people to review the registration site, and to register as soon as the registration is open (which I absolutely encourage you to do). This will be the first connectathon that I won’t be at – which is kind of sad, but had to happen at some point.

Although I’m in the middle of a series of posts on FHIR & XDS (and a bit behind to tell the truth – work has got in the way of the fun stuff), I thought that it might be of interest to discuss some ‘connectathon-related’ topics – starting with the conformance resource. We’ve talked about this before in the context of a server using it to indicate to a potential consumer what it’s capabilities are (and been quite good in actually producing examples in our discussions), but it has also been designed for use by a client to indicates what it requires of a server.

In the case of connectathon, we encourage clients to create a Conformance resource to indicate what they need of a server as they fulfill the scenarios.

The conformance resource itself has some ‘header’ information (eg description, FHIR version and so forth) and then entries for REST, Document and Messaging. We will focus on the REST entry. There are entries that indicate:

  • Whether the conformance resource is describing a client or a server
  • Which resources the server supports or a client requires
  • Which profiles are supported/required
  • Security considerations
  • For each resource:
    • what operations are supported/required – CRUD
    • whether history is supported/required
    • the search parameters supported/required

A client will set the Conformance/rest/mode/@value  value to ‘client’ to indicate that it is specifying a requirement rather than a capability – and the other parts of the resource mean the same thing that they to for a server.

As an example, suppose that I want to complete scenario 1.4 of connectathon (search for a patient on name)  – the following conformance resource would indicate my requirements to a prospective server:


<Conformance xmlns="http://hl7.org/fhir">
     <text>
         <status value="generated"/>
         <div xmlns="http://www.w3.org/1999/xhtml">
             <p>A conformance statement detailing the client requirements for a sever in implementing scenario
             1.4 on connectathon#5 - search for a patient by name. Note that this only for 1.4 - we'd need
             to update if we were supporting any other scenario</p>
         </div>
     </text>
     <identifier value="68D043B5-9ECF-4559-A57A-396E0D452311"/>
     <version value="20130510"/>
     <name value="Connectathon Conformance requirements"/>
     <publisher value="HayCorp"/>
     <telecom>
         <system value="email"/>
         <value value="user@haycorp.com"/>
     </telecom>
     <description value="This is the FHIR conformance statement for the haycorp team at connectathon #5"/>
     <date value="2013-11-12"/>
     <software>
         <name value="HC-Client"/>
         <version value=".01"/>
     </software>
     <fhirVersion value="0.12-1911"/>

     <!--   doesn't really apply for a client, but is required   -->
     <acceptUnknown value="false"/>

     <!--   we only do XML -->
     <format value="xml"/>

     <rest>
         <mode value="client"/>
         <resource>
             <type value="Patient"/>
             <operation>
                 <code value="read"/>
             </operation>
             <searchParam>
                 <name value='name'/>
                 <type value="string"/>
                 <documentation value="Search by patient name"/>
             </searchParam>
         </resource>
         <operation>
             <code value="search-system"/>
         </operation>
     </rest>

 </Conformance>

A couple of notes:

  • The conformance resource is not – necessarily – used for machine processing, but rather as a uniform way that servers and clients can indicate and match capability & requirements. For example, they are very useful in the planning stages of a project when clients and servers are being located and/or designed.
  • As a FHIR resource, a conformance statement can be stored in a FHIR server, and has the same versioning capabilities as any other FHIR resource. This makes an excellent choice for locatable documentation once the systems are in operation.
  • And its resource nature also supports the concept of a searchable registry. This is more applicable to a server than a client, but does support the idea of providing UDDI like functionality…

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>

Adventures in FHIR Searching: Getting a list of patients in a Ward

Had an interesting set of exchanges on the implementers skype chat yesterday talking about searching in FHIR.

The background was that we are looking at building a tablet app to support the recording of medication dispensings. Orion has an application (a Hospital Information System or HIS) that records this using a desktop interface, so the plan is to build a FHIR server that will act as a ‘proxy’ between the HIS and the tablet, with the tablet app consuming JSON FHIR resources over a RESTful interface.

We are thinking that the user will log into the tablet, then get a list of the wards they are currently scheduled on. They will select a ward, which will give them a list of patients, then select the patient from which they will get the medications to administer (or a similar type of workflow). I was asked to help out with the design of the FHIR resources & calls – and started to think about how to get as far as the patient list (I’ll consider the medication administration stuff later).

Looking through the current FHIR resource list I found a Location resource that specifically mentions that it models a Ward, so my first thought was to add an extension to that resource of type List, and then the List could reference a collection of Patients. The proxy server would be responsible for communicating with the HIS and constructing the bundle of these resources, which could be returned to the tablet app on request.

I mentioned this on the skype chat, and after some discussion with Grahame and Lloyd, we figured that a better solution would be to model the relationships using an encounter, and then we could do a FHIR query to get the data we need, using an _include parameter on the query for efficiency (I’ll get to this later).

So the relationship between the resources is like this:

ward query

Our approach will be:

  1. get the ward we want
  2. then get the encounters that are associated with that ward
  3. and then we can get the patients from the encounter.

Getting the ward is a straight forward query. Suppose the name of the ward is ‘Ward1’ then it’s a simple GET query against Location:

GET /Location?name=Ward1

Note that we will get back a bundle, and we may need to check for multiples – eg Ward1 and Ward11 would be valid matches (it’s a string search). We might also want to include a Location.type parameter if that is appropriate in our situation. But, we now have the Location resource– the Ward – and the ID of that resource. Let’s pretend the ID is 100.

Now to get the Encounters associated with that Location. Encounter does have a location property which is a sub-object with properties of Location & Period. In other words, an encounter can have many locations, and each location has a period over which the location was valid. This makes sense of course, as a patient can be moved around different places (Wards, radiology, therapy etc). So, we want encounters that are associated with our specific Location (Ward) right now. (There are other subtleties, but let’s keep it simple for now). We’ll assume that if there is a Location that matches ours, and where the period.end property is not present then that means they are currently associated with our ward.

However, there is a problem: There is no search parameter defined for location against Encounter – and in fact we need 2 of them – one for the location.location property and one for the location.period property. There are 2 things we can do:

  1. Petition the FHIR team to add these parameters
  2. Make these search parameters that our server supports (which is quite legitimate, though does mean our query on’t work on other servers)

We will do both. We will define 2 search parameters:

  • location that matches Encounter.location.location (which is a reference)
  • location-period that matches Encounter.location.period (which is a date).

and also ask the core team to add them (actually it is the HL7 committee that has oversight of this resource – you can look this up from this page, but sending a message to the core team via any of the supported channels will achieve this).

So now we have:

GET /Encounter?location =100 &location-period => 25-10-2013

(assuming that the date today is 25th October 2013)

So, now we have the encounters we want – all we need are the patients.

We could make a query for each patient – we can get that from Encounter.subject – but we can also ask the server to do that in our query by using the _include parameter. This is an instruction to the server to include the referenced resources in our query as well as the directly matched resources. So our complete query is:

GET /Encounter?location =100 &location-period => 25-10-2013&_include=Encounter.subject

will return a bundle that will contain all the encounters currently associated with Ward1 (resourceID=100), plus all the patient resources that are in these encounters. Job done!

Some notes:

  • We have defined some server specific parameters. Should the committee decide not to add these parameters to the spec, then either we accept this (after all we’re only concerned with our server at the moment anyway), or we could re-jig the query. Another exercise for the reader…
  • Servers are not obliged to support all search parameters – even if they are named in the spec. If we wanted our client to be able to talk to another FHIR server, then we would need to examine its conformance resource to make sure it does.
  • Servers are also not obliged to honour the _include parameter. If they don’t, then it simply means that we have more work to do client side – we just make direct requests for each patient after we retrieve the encounters.
  • In an earlier version of this post I was querying ‘into’ search parameters – eg GET /Encounter?location.period=… – it doesn’t work like that – it’s not like a path. Part of the issue is that we can’t have ‘ad-hoc’ queries into resources  – to quote Grahame: we’ve agreed that clients can’t simply launch random queries into the content of the resources – it has to be pre-agreed fields – there’s no way for the server to make that efficient, except in the case of special technologies 
  • Date querying is complicated. There’s a whole section in the spec on it.

This became a rather longer post than I intended, but hopefully it is a useful exercise to run through the thinking behind what became quite an elegant query – and I learned a lot doing it. It’s not the only way to do it of course, but it was a fun process!