Decomposing a FHIR document

Scenario 2.3 of Connectathon talks about a server ‘decomposing’ a FHIR document. This is another of those huge topics, as it is all about using the document as a ‘carrier’ for information that is used by a recipient to update their own data stores, rather than simply storing it as a ‘blob’ to be displayed to a user on request.

The issue is not so much a technical one – that’s relatively straightforward (though one of the more complex in FHIR) – but rather relates to the purpose of a document as a ‘summary at a point in time’ – or as a ‘snapshot’, rather than a mechanism to ‘transfer state’.

To illustrate, suppose you are an EMR (Electronic Medical Record system) and you receive a discharge summary from a hospital that contains a list of Medications on discharge – 5 medications in all. Suppose further that  your own record of the patients current medications has those 5 and one more – what do you do with the one that is not in the document? Is it safe to assume that it was stopped while in hospital and discontinue it? – probably not. What needs to happen is that a human needs to review the 2 lists – preferably with the patient in front of them and ‘reconcile’ the two lists to decide what the correct list should be.

There are ways to assist this process – for example the document could explicitly state that a medication has been stopped (the FHIR List resource has a way of explicitly stating this), or the document might contain a list of medications on admission – the document recipient could compare that with their current list to infer if the drug was stopped.

Now this is not to say that you shouldn’t use a document for this purpose – documents will often be the simplest way to move this information around – one of the reasons CDA is so popular, but you do need to be careful when you do, aware of the issues that are involved and quite explicit about what the behaviour of a recipient is.

Enough of that – let’s talk about the technical aspects.

Quite simply, by POSTing the document to the root of the server, the server will treat it as if it were a transaction – it doesn’t perform any document specific logic (although it is possible to reconstitute the document afterwards). We’ve actually used this transaction ability before when there is more than one action to perform as a unit, though processing a document bundle is the most complex we’re approached thus far because there will be many internal references within the bundle, and also a mixture of new and existing resources.

And transaction processing can be quite complex anyway…

To summarize how the server should process the resources within the document bundle (and refer to the details in the specification):

  • If the resource is known to be new (it has a cid: ID) then it should be treated as a create operation. (There is a variant for when the resource might exist, where the bundle can specify a search parameter – see the spec for more details, we’ll ignore if nor now). Because there may be internal links to the resource, then any references to that resource (eg from the composition) will need to be updated within the document before the local stores are updated.
  • If the resource is an existing one on the server, then it should be updated by the version in the document. Note that a server can enforce ‘version aware’ updates – where the currently correct version of the resource should be given in a <link> element  for the entry – e.g. for a Condition being updated this might be:
<link href="http://localhost/Condition/788/history/1" rel="predecessor-version"/>
  • If the resource is an existing one, but on a different server, then the server needs to save it locally (and assign a new ID). This will also require updating any internal references to that resource within the document.

So processing the document (transaction) will likely need multiple ‘passes’ to correctly process. (I’ve not actually written this sort of functionality, so happy to defer to those who have if I’ve got this wrong).

At the end of the process (after updating all the local stores), the server needs to return a bundle that contains all the assigned ID’s (but not the content). In other words, the bundle returned will have the same number of entries as in the document, but each entry will contain only:

  • The server assigned ID in the id element – <id>{uri}</id>
  • The version specific id in a <link rel=”self” href=”{uri}”/> (if the server supports vread)
  • The client assigned id in a <link rel=”related” href=”{uri}”/>
  • <title> and <updated> as required by the atom spec

So, at the end of this process, all the resources that were in the document have now been saved on the server – either as new resources or updates of existing ones. For example a client could submit a document containing a new Condition, and after successful processing, query for that Condition directly using standard FHIR queries.

Another example might be the ‘Current Medication List’ Use case that we discussed earlier, that uses a List resource to indicate the list of medications a person should be taking (and we discussed this in an earlier post). You could imagine a workflow that records a Progress Note – updating this list, creating an encounter  and establishing a link to the document where it was changed like this:

  1. The clinician queries the List resource to get the current list of medicines.
  2. They examine the patient and decide to update the list – stopping one medication and starting another. They construct a document to record this. The document bundle contains:
    • A Composition. The encounter property is set to the encounter (see below). Subject and participant properties to the correct resources. Section entries to the Observation and the List resource.
    • A Patient
    • A Practitioner
    • An Encounter with subject and participant properties set to the appropriate resources in the bundle
    • An Observation with the clinical findings. It has an extension pointing to the Encounter
    • The MedicationPrescription to be stopped, with the status property set to stopped
    • The details of the new MedicationPrescription
    • A List resource where the entry pointing to the medication to be stopped has deleted set to true (and possibly an extension with the reason). The List resource also has an extension that points to the encounter (or maybe the composition).
  3. The document is sent to the server which updates all the resources

Afterwards, to get the current list of medications, a search on /List (with the correct parameters) will return the current medication list, which is traceable back to the encounter where it was updated, and the Progress Note.

Now there are doubtless better ways to do this, but you get the idea.

If there were any errors – for example invalid resources or where a server is implementing version aware updates and a version update fails – then the server will reject the update in its entirety, and return an error response. The actual error code will depend on the nature of the error – eg a 409 if there were a version conflict.

Note that the spec states that “Any resource referenced directly in the Composition SHALL be included in the bundle” but that the inclusion of indirectly referenced resources is up to the implementer. This implies that one of the reasons for failure could be resources missing from the bundle  that are directly referenced by the Composition. Error response 422 (Unprocessable entity) would be a valid response in this case.

It would be courteous for the server to return an OperationOutcome resource with details of any error, though this is not dictated by the spec.

To ‘re-constitute’ the document from the ‘shredded’ resources , you can:

  • GET the composition
  • GET all the resources that the composition references – and recursively all of the resource they reference as well.

So while certainly feasible, you’d probably want to store the original document as a ‘blob’ as well (and this way also preserves any signature).

About David Hay
I'm an independent contractor working with a number of Organizations in the health IT space. I'm an HL7 Fellow, Chair Emeritus of HL7 New Zealand and a co-chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the FHIR standard. I'm the author of a FHIR training and design tool - clinFHIR - which is sponsored by InterSystems Ltd.

Leave a Reply