FHIR XDS – updating a document

It’s not uncommon for a document to need to be updated after it has been posted to a repository and registry. Sometimes new information has come to hand that affects the document, or there may be normal workflow where a ‘draft’ document is saved, and is subsequently updated or finalized, or maybe the original was just plain wrong and needs to be retracted.

None of these are unique to a document of course, but there are some ‘quirks’ – for want of a better word – to the DocumentReference resource for a couple of reasons:

  • It is a resource whose main role is to refer to another entitity – so there are 2 lifecycles to consider.
  • Documents are often summaries of clinical care (e.g. Discharge Summaries, Progress notes, Clinic notes) and it’s very common for clinical decisions to be made on the contents. Keeping an easily accessible (to the end user) ‘audit trail’ of changes is very important for medico-legal reasons.

When thinking about changes to a document, there are 2 ‘types’ of change to consider:

  • Changes to the metadata (e.g. the document type was incorrect)
  • Changes to the content of the document itself.

We’ll consider these separately.

Changes to the metadata

If the change is only to the metadata – the contents of the DocumentReference resource itself, then it can be updated it in the usual way – i.e. retrieve the existing version, make the changes, and PUT the document back. The standard FHIR versioning process will manage the update of the resource. (Resource versioning is not required by FHIR – but highly recommended). There are some caveats to this approach, as mentioned in a minute…

Changes to the document.

This is more tricky. What we need to do is:

  • Update the document in it’s location (e.g. as a binary resource on a FHIR /Binary endpoint)
  • Update the existing DocumentReference resource that points to it, setting the status property to ‘superseded’
  • Create a new DocumentReference resource that references the updated document (and if it’s a FHIR server that we may want to make this a version specific reference), setting the relatesTo.code to ‘supercedes’, and the relatesTo.target as a reference to the original DocumentReference resource
  • We might also want to create a provenance resource to indicate who has made the change.

Because this needs to be managed as a transaction, we’ll use a FHIR bundle and we’ll use the same pattern as when we submitted the document in the first place – i.e. have the repository server manage the updating process. (Other patterns are possible of course).

So our bundle will contain:

  • The updated document as a base-64 encoded binary resource. It will have a real ID so the server knows to update it
  • The original DocumentReference resource, with updated status. It will also have a real ID so the server knows to update it
  • The new DocumentReference resource – largely a copy of the original with the relatesTo property set. It will have a ‘cid:’ ID so the server knows to add it as new.
  • Optionally a provenance resource with the details of who made the change – and when. The provenance resource refers to the resource being changed (not the other way around) so it will have 2 targets – the 2 DocumentReference resources that are effected in this transaction. It also has a cid: ID.

The repository server will process the bundle as described above.

Although this second approach is more complex, it does make it quite obvious that a significant change has occurred. For this reason, some metadata changes – such as a change of subject or author – might be better managed this way rather than a simple update to the DocumentReference resource. It’s up to you…

All of this does raise an interesting point that we didn’t think about when considering how to query the registry for documents (i.e. a query against /DocumentReference) – the response will include DocumentReference resources that have been superseded as well as current ones.

If we don’t add the status parameter in the query, then we will get back all DocumentReference resource’s – so we will need to check this value when assembling the list of documents for the consumer (Of course, we may want to do this anyway so that we can place some visual indication in the display that changes have occurred – it’s up to the implementer, as it should be…)

Otherwise we can be explicit that we only want current documents, so the examples we gave in the previous post becomes:

GET  http://registryserver/DocumentReference?subject= 100&status=current&period > 2013-01-01

and

GET  http://registryserver/DocumentReference?subject= 100&status=current&type= http://loinc.org|34108-1

And as a last word, and following on from the post that Keith Boone made about task orientated services, we may choose to define specific service end points for this functionality (and even for the ‘add document’ scenario), perhaps:

  • /service/document/new
  • /service/document/update

both of which receive the bundles we’re described.

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…