Slicing extensions with FHIR

So recently I wrote about a simple ‘extensions editor’ that we created to allow our Orion Health developers to create Extension Definitions (actually StructureDefinition resources of course) to describe the extensions they were creating when developing FHIR interfaces. I assumed that they were all ‘simple’ extensions – that is an extension that just had a single value – rather than extensions that were nested inside other extensions. Wrong!

These are  defined using ‘Slicing’, – so I needed to find out more about that works, and then implement it.

Slicing is one of the more complicated parts of FHIR (and I don’t fully understand it yet!). At its heart it’s all about taking resource elements that can appear more than once – and then being being more prescriptive about what the list contents can be in a particular profile. (That’s a gross over-simplification of course – check out the spec for more details).

An example in the spec is that of a Blood Pressure – where you take the Observation.component element, and say that for this profile (technically a profile on Observation) we only want 2 component elements – one for the systolic and the other the diastolic – and defines the codes that should be used.

So in the profile (StructureDefinition) you first define a thing called a ‘discriminator’ – how to be able to tell the slices apart. The discriminator defines what the ‘unique’ property is in the slices.

Next, you create a group of elements for each slice that defines the contents of each slice – the value of the discriminator, the data type, multiplicity and so forth. There are a number of examples in the spec that show how this works.

For extensions the discriminator should (?must) be the url – so that’s one thing settled, but I still wasn’t completely clear about what I needed to do, so I decided to take a look at the extensions that were defined in the spec, and use those as a guide. I updated the extension editor component in clinFHIR to show these extensions.

Take a look at the following screen shot.

citizen - summary

It shows the detail page from the extension ‘patient-citizenship’ – we can see that the extension is to be applied to the Patient resource, and that there are 2 ‘child’ components – one called code (of type CodeableConcept) and another called period (of type period). So this extension is to allow a patient to claim citizenship of a particular country over a given period. (Incidentally, the CodeableConcept ought to be bound to a ValueSet – not that I’m criticizing, mind… 🙂  )

btw – the ‘official’ description of this profile can be found here – all of the profiles defined in the spec are found from a link at the top of each resource description.

But what does this look like under the hood? How are the ‘child’ slices defined? Click on the link that says ‘Raw Elements’ and you get this page:

citizen - raw

This view shows all the elements in the StructureDefinition.snapshot property – ie all the elements contained in this profile – an extension that has 2 child properties. There are quite a few elements here, but they do make sense (after a little while!). Lets walk through them. (If you are really interested then you can start the extensions editor, select this profile and check it out for yourself.

  • The first element (path = Extension) indicates that the extension is at the ‘root’ of the resource – as opposed to an element within the Patient resource.
  • The next element (Extension.id) is provided to allow internal referenceing of this element from within the StructureDefinition. I’m unsure when this is used.
  • The third element (Extension.extension) – which is the one showing in the right hand box – is the discriminator. You can see at the top that this is set to ‘url’ (always the case with extensions, but can be different in other profiles – as it is in the Blood Pressure example).
  • After this there are 2 sets of 5 elements each. These describe each slice. Each slice contains the following:
    • Extension.extension. In other words, the ‘child’ element is an extension on the parent extension
    • Extension.extension.Id. Similar to the Id on the ‘parent’ extension, this is to allow references to the element from within the profile.
    • Extension.extension.extension. This would be where an extension on the child would sit – i.e. an extension nested to another level. This is perfectly legitimate in FHIR – though it’s starting to get quite complicated – pity the poor client that needs to make sense of it! In any case, note that the multiplicity is 0..0 – in other words we are explicitly stating that this is not permissible in this profile.
    • Extension.extension.url. This is the unique value for this slice (recall that the discriminator is ‘url’). If you look inside it (using clinFHIR) you’ll see that there is a property called ‘fixedUri’ whose value is ‘period’. In other words, a conformance resource will have the ‘url’ value for this element set to the value ‘period’
    • Finally an element with the path Extension.extension.valuePeriod. So the datatype for this child element is a period.
  • Next up is an element Extension.url. This is the url of the ‘parent’ extension and also has a fixedUrl property – in this case set to http://hl7.org/fhir/StructureDefinition/patient-citizenship – the url for this whole extension
  • And finally an element with the path Extension.value[x]. This is where the value would go in a ‘simple’ extension (one without children). Note that the multiplicity is 0..0 – an extension can have a value, or child extensions, but not both.

(Actually I’m not sure why the last 2 aren’t in positions 4 & 5 which would seem to make more sense. It may be just that that’s where the build tool put them, or they may need to be at the end).

It pays to have a play around using the tool against the extensions defined by the specification – it does take a little time to get your head around this stuff – at least it did for me! You can also compare what clinFHIR shows for an extension with what the specification does. I have to admit that the spec is prettier – but it doesn’t show this level of detail, which is what I was after.

So that’s how it’s done (at least, I think that’s how it’s done!)

To create your own complex extensions using the extension editor, follow these steps.

  1. With Grahames server selected as the conformance server, click on the ‘New Extension’ button at the top of the form.
  2. Enter the name and description for the extension. Remember that the url for the extension will be derived from the name – if you choose one that is already in use you will get a warning – best to choose another name. You can also enter any of the other elements that are needed – eg the Resource Type that this extension applies to.
  3. Where it says ‘Extension type’, click on the button labeled ‘complex’ (top middle of the form) and a new tab will appear labeled ‘Complex Contents’. Select that tab.
  4. For each child extension enter:
    1. The Name (make it a single word – this will be the value of the url in the profile, which is the discriminator). It must be unique as well.
    2. The short description
    3. The Multiplicity
    4. The DataType. If you select a coded value you’ll have the opportunity to select the ValueSet to bind to it.
    5. Make sure to click the plus (+) symbol to the far right to add the contents of the row as a new child extension.
  5. You can click the ‘Validate’ button at any stage to check that the profile (StructureDefinition) is valid. This uses the validate operation – quite handy actually!
  6. When finished, click the Save button to save the new profile to the server.

And that it! You can select the profile and see what elements have been created (I hope they are correct – if not, then I hope that someone will correct me!)

Of course, you don’t need to know any of this stuff to use FHIR. Tooling is provided by the project that will create these definitions (Forge and the specification build tool itself) and also to validate that a particular resource is conformant to one. But it’s good to know what’s happening ‘under the hood’!

And, as always a disclaimer that clinFHIR only supports a fraction of the functionality defined by the specification – and implemented by tooling such as forge. In fact, if you do have a play you’ll find that it won’t update any extension other than ones created by clinFHIR – for that very reason.

Now I need to update the resource builder to cope with complex extensions. Sigh.

 

 

 

 

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

%d bloggers like this: