Using FHIR to expose a Patient Identity Registry lookup service – part 2

In the previous post we discussed the use of the patient resource as part of an Identity registry service. In this post we will discuss the behavior of that service.

To review the specific scenarios we are supporting:

  1. Retrieving a list of matching patients based on criteria such as name, gender, Date of Birth and such like.
  2. If we do have an identifier, retrieving the resource (or resources) that have that identifier.

1. Searching for a patient

The first scenario is a simple search – as we have already discussed. We’ll support searching on name, gender and age. The spec gives the details of these search parameters.

Name is straightforward – it is a string and the spec states that the server will match our string with both family and given names which have that string within the name. The following GET request will return all patients with ‘eve’ in their name.

http://hl7connect.healthintersections.com.au/svc/fhir/patient?name=eve

Gender is a token. Reviewing the bindings for gender we see that the options are currently ‘M’, ‘F’ or ‘UN’, so the following GET request will return all males with ‘eve’ in their name

http://hl7connect.healthintersections.com.au/svc/fhir/patient?name=eve&gender=M

Age is a bit trickier. We could always use Date of Birth (and maybe we should) but often we’ll only know approximately how old a person is. For this to work we’re going to need modifiers on the query. I won’t describe the details (refer to the spec for that), but basically you can do things like specify before and after as shown in the example below for a child less that 3 years old (The users UI should be able to create dates from ages without difficulty).

http://hl7connect.healthintersections.com.au/svc/fhir/patient?birthdate:after=2010-01-01&birthdate:before=2013-12-31

Couple of notes:

  • I’ve used Grahames server rather than the elbonian example I used in the previous post so you can try it out for yourself.
  • Also, the last query actually returns an animal – at least it did when I tried it. FHIR supports veterinary as well as human health information.

Naturally the response for all of these examples will be a bundle of patient resources, as previously discussed.

2. Getting the details when the Identifier is known

So finding a patient by searching on name or other parameters is straightforward. What if we already know the identifier? We can just GET that patient resource, right?

Well, no we can’t. We still need to do a search, except that the parameter we are using is the identifier. If we stop to think about it for a second it is obvious why. We can only retrieve a resource directly if we know its ID – and therefore its URI. But the ID and the identifier are not the same (as we discussed in the last post) – so a search is needed, and we will get a bundle back – hopefully with only a single resource in it.

Try the following link:

http://hl7connect.healthintersections.com.au/svc/fhir/patient?identifier=444222222

When I tried this I got a couple of resources back – well it is only a test server. But – this does point out that FHIR does not enforce the ‘uniqueness’ of an identity – it is the responsibility of the application behind it that does that.

But there are still a couple  more things to consider.

  • First, depending on how we configure the server, we may or may not get inactive records back. Recall the merge example in the last post, where we merged WER4568 with PRP1660 – de-activating WER4568. What should we get back if we search for WER4568? It makes sense to still return the resource, but it does mean that we need to check the ‘active’ property when we get it to make sure it is still in use (and we can use the link property to get the resource to which it was merged if not).
  • We also need to think a bit about the details of the identifier search. It’s a token, so if we just search on the value, there’s a chance that the same identifier could exist in different namespaces. To be safe we need to specify the namespace as well as the value – thus the identifier parameter for PRP1660 becomes something like www.moh.elbonia.govt/nhi/PRP1660 rather than just PRP1660.

So we’ve got a REST service that allows us to query a patient identity service using simple GET requests and supporting a number of parameters.

What about Security & Privacy? We won’t consider these yet. They depend on a number of aspects of FHIR that we have yet to discuss such as tags and oAuth – we’ll revisit this topic when we’ve done that.

But we can create a conformance resource. This is a resource that can be used by both server and client – but we’ll just think about the server at the moment. The conformance resource allows a server to declare – in a computable way – what resources it supports, and what actions against those resources. Here is an example:


<Conformance xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://hl7.org/fhir">
   <text>
     <status value="generated"/>
     <div xmlns="http://www.w3.org/1999/xhtml">
       <p>This conformance statement id for the Patient Identity service for the Elbonian Ministry of Health</p>
       <p>The Registry supports the Read transactions for the resource Person.</p>
     </div>
   </text>

   <identifier value="68D043B5-9ECF-4559-A57A-396E0D452311"/>
   <version value=".1"/>
   <name value="Elbonian Patient Registry Conformance statement"/>
   <publisher value="Elbonian MOH"/>
   <telecom>
     <system value="email"/>
     <value value="wile@elbonia.govt"/>
   </telecom>
   <description value="This is the FHIR conformance statement describing the Patient Registry for the
     Elbonian Ministry Of Health.
     It allows a user to search on patients, and retrieve the details of a patient based on their identifier.
     No security is required as Elbonians do not have any concept of privacy"/>
   <date value="2012-10-14"/>
   <software>
     <name value="PatientRegister"/>
     <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 -->
   <rest>
     <mode value="server"/>
     <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>

The conformance resource allows a potential client to understand the capabilities – and requirements – of our Registry service. It should be self-explanatory, so I won’t go into it in much more detail. However conformance statements – and the associated concepts of profiles – are a lot more powerful than this, and will receive more attention in due course. In some ways, they are analogous to UDDI and WSDL in the SOAP world – but much easier to understand.

According to the spec the server should deliver this resource in two way:

  • GET [base]/metadata {?_format=[mime-type]}
  • OPTIONS [base] {?_format=[mime-type]}

Thus a GET to :

http://hl7connect.healthintersections.com.au/svc/fhir/metadata

will return the conformance statement for Grahames server, and hopefully you can imagine what the equivalent for the elbonian server would be.

(The reason why there are two ways is that while the GET method is pretty much universally supported by HTTP clients, the OPTIONS method is not.)

Well, that brings us to the end of this short series (2 posts) on FHIR-enabling a patient registry service. We now have a “simple to use” service that allows any user to search our patient registry using standard tools – either from the command line of as part of an application. We could easily extend it to support updates as well – perhaps when a patient changes address or contact details these updates could be applied directly using a PUT against the resource URI. If we did allow such a thing, then authentication and authorization become a lot more important – and we’d probably also want to have some sort of person mediated workflow and checking involved rather than just a direct update. But the point is we can do that if we choose to do so.

Although fairly high level, hopefully this gives a ‘real-world’ example of where FHIR can add real benefit in health interoperability, as correctly identifying the patient is the cornerstone of accurately recording health information.

Next post will be back to basics – the codeableconcept datatype deserves some attention…

Using FHIR to expose a Patient Identity Registry lookup service – part 1

Now that we’ve covered a bit of the theory and background to FHIR, let’s look at a concrete example of where we might apply these principles. The Use Case we’re going to look at is to provide a REST based lookup service in front of a patient Identity Server.

Some notes before we start:

  • We assume that there is already an existing registry that we are providing a front end for. It handles all the assigning of identifiers, managing merges & un-merges and such like. In other words this is a read-only service (at the moment).
  • Every patient will have a single identifier (although that may change over time). We’re going to assume that this has national scope so we’ll call it a National Health Identifier – or NHI. This won’t apply in all domains of course, but it simplifies the issue for now.
  • So that we can create full URL’s, we need a server name. We’re also going to need some namespaces (more on that shortly) so, in a nod to Dilbert, we’re going to assume that the country we are building this for is elbonia.

The scenarios we will support are:

  • Retrieving a list of matching patients based on criteria such as Name, Gender, Date of Birth and such like – what you’d use if you were wanting to find someones NHI.
  • If we do have an NHI identifier, retrieving the resource (or resources) that have that NHI.

This is going to be a rather long post, so I’ll split it into 2 separate posts:

  • In this one we’ll talk in some detail about the resource, and cover the special importance of the datatype of the properties of the resource, and how to manage merging where we have duplicates.
  • In the second post, we’ll talk about the behavior of our registry service.

First, which resource to use? Well, the obvious candidate is the patient resource. It has the base demographics we need, plus an identifier (in fact multiple identifiers).

This is the first time that we’ve looked at a resource in any depth so it’s worth spending a bit of time on it. Each resource has a specific page in the spec, and each page has a number of sections:

  • A description of what the resource is intended to represent. The size and content varying according to the complexity of the resource.
  • A UML representation of the resource – a class diagram – containing the core properties with the property name, multiplicity and datatype. The datatype of the property is especially interesting as it can range from a single string to a more complex structure – an object in its own right. We will see more of this structure as we explore the patient resource, but it’s important to realize that the datatypes are the same for all resources.
  • A XML representation of the properties with the same information as the class diagram – with the addition of a brief description of each property. The name is hyperlinked to a formal description, and the datatype/s hyperlinked to the detailed description of the datatype. (Many resource properties allow multiple datatypes – you choose which one is the most appropriate when creating – or updating – the resource).
  • The terminology bindings for those properties that are bound to a code set or terminology.
  • Other constraints – generally those that cannot be represented by XSD schema.
  • Any other comments of note.
  • The specific search parameters defined for that resource.

Each resource will also have a specific XML schema and schematron file – these can  all be downloaded from the spec in a single zip file.

Of the main representations, I find the XML format the easiest to follow, so let’s look at some of the properties for the patient resource (at least those that have special points to discuss).

Patient.identifier

First up is the identifier property. This will hold our NHI identifier (though it can have others as well – e.g. a drivers license). If you look at the XML, you will see that the datatype is also called Identifier (it is in a green font, and is a hyperlink). Click on that link – it will take you to the description of what an identifier datatype is, and what properties it has.

There are a few that are of interest to us (and note that it is extensively hyperlinked to get more information as you need it).

  • The use property describes how this identifier is going to be used. We’re the official registry so ‘official’ seems most appropriate – but we note with interest that ‘temp’ or temporary might also apply in some scenarios.
  • The label is for humans – so let’s use NHI for that
  • The system needs to define the namespace within which the actual identifier value is valid – and unique. It’s a URI, so let’s base it on the address for the Elbonian Ministry of Health – so we get http://nhi.moh.elbonia.govt (Note that this doesn’t have to be a ‘real’ address, so long as it is globally unique).
  • The actual value of the identifier – eg PRP1660, or whatever we choose to use. FHIR makes no comment about the format of the identifier – that’s up to the implementation. We might decide, for example, to incorporate a checksum digit to help with error checking.
  • The period over which the identifier is valid. That could be useful if we have to ‘retire’ an identifier, but for now we’re going to assume that if our service returns an identifier it is currently valid and is intended to remain so, so we won’t use it for now.
  • We could use the assigner to give more data about the organization that maintains the registry.

Patient.name

Next property is the name of the patient. It has a datatype of HumanName, and contains properties such as family name, given name and use. There is also a text property that can be used for the complete name. Whether the text property and/or the individual items are used is at the discretion of the resource author, although profiles can be used to control usage to some extent.

This is a good place to mention that you could – if you needed to – use extensions to add other properties to datatypes. For example, you might want to add a salutation to the name. I’ll talk more about extensions in another post.

Patient.gender

This has the datatype of codeableconcept. Codeableconcept is an incredibly important datatype as it represents coded data and is extensively used within FHIR. It deserves its own post, so for the moment I’ll just point out that there is a particular set of codes that can be used here (if you look in the terminology bindings section you will see a reference to the set).

Patient.link

Patient identification is a critical part of recording healthcare information – and one that is prone to error, for example a single person being registered multiple times. The link property in FHIR us used to assert that two (or more) patient resources are, in fact the same person.

And now is a good time to describe the difference between resource ID and the identifier.

As described in previous posts, all resources have an ID – the resource ID – which  along with the server and resource type comprise the unique URI of the resource. The resource ID cannot change, and so something like the registry identifier is not a good candidate for the resource ID because it can change. You should think of the resource ID like a database primary key – let the server assign it, and attach no semantic meaning to it. (A client can also assign the ID – though you need to be careful if doing this).

An example might help.

Suppose you create 2 patient resources. One has the ID of 100 with an identifier of PRP1660, and the other has an ID of 200 with an identifier of WER4568. After storing clinical data against these resources (and using the resource ID as the linking mechanism) you discover that they are actually the same person. You determine that the identifier you wish to keep is PRP1660, and wish to ‘shift’ all the records currently pointing to WER4568 to point to PRP1660, and inactivate WER4568. You cannot (or should not) change the ID in the resource reference of all the other resources that currently point to WER4568. The correct action is to set the link of each patient resource to the other one (thus they point to each other), and set the active property of WER4568 to false. This should be done in a transactionally safe manner.

In this way it is obvious to any subsequent view of the record what has happened, and which is the correct resource.

Before merging

Identifier ID Active link
PRP1660 100 True (or absent)
WER4568 200 True (or absent

After merging:

Identifier ID Active link
PRP1660 100 True (or absent) 200
WER4568 200 False 100

(Note that the link is actually a resource reference, and so has a slightly more complex format than a single string)

And while we’re talking about errors, what do you do if – rather than having duplicated patients, you just set the subject link of another resource (say a condition resource) to the wrong patient? Well, that is what the versioning facility in FHIR is for – you create an updated version of the condition resource with the ID of the correct patient resource, thus maintaining the history of change.

The other properties are all important but I won’t talk any further about them here, as their meaning and use should be evident from their description and from the discussion above.

It’s also worth pointing out that in a real scenario, if there were properties that we needed and weren’t in the FHIR specification (for example the reason for a merge, or to store realm specific information like iwi), then we can always use the extension mechanism to add them.

Well, that is all we’re going to say about patient – next post will describe how we use the patient resource in our registry REST service