So you want to create a FHIR extension?
April 12, 2017 1 Comment
Most people familiar with FHIR will be aware of profiling resources – and in particular adding new elements to resources for a specific use case – adding an extension. It seems straightforward, but there are a number of things to think about when you do this so – or so we’ve found at Orion Health!
In this post we’ll talk about some of the factors involved – less about the technology and how they work in FHIR and more about some of the design time issues.
Before we start, let’s define a few of the terms we’ll be using.
The Extension Definition is the resource that will hold the definition of the extension. It’s actually a StructureDefinition resource.
The Profile is how we ‘attach’ the extension definition to the resource. It’s also a StructureDefinition resource, but we won’t discuss profiling further here.
The ValueSet is a resource that describes a set of concepts that are the possible values for a coded element. The ValueSet actually refers to one or more CodeSystems that describe the actual concepts. A ValueSet is bound to the element, which determines whether values must be in the ValueSet
The CodeSystem contains the list of actual concepts – each of which has a code. The CodeSystem might simply be a description of an external terminology (like SNOMED or LOINC), or it might actually contain the definition of those codes.
A system is a ‘child element’ found in Identifiers and coded elements that links the element to the set of permissible values (and the code value will be unique within that system). It’s like a namespace – in the case of an Identifier it is defined in a NamingSystem resource, for a coded element it’s the Url of the ValueSet. Technically, it’s a URI.
A NamingSystem resource is used to describe a code system or identifier system. It’s not the actual code/identifier system itself, but rather “Defines a specific code system or identifier system, so that it can be noted in a registry for other systems to find and understand an identifier”.
Here’s a flow chart that gives an overview of the process of creating an Extension Definition. And a reminder that this is not an ‘official’ FHIR recommendation – I take full responsibility for errors or omissions!
So we start by Confirming Requirements – what is it that we are wanting to represent? It pays to spend a bit of time to get this right – and to consult as widely as possible. At Orion, we use an internal wiki to describe what we want it to do and to record comments and feedback, but we’ll also go out to the community (via the FHIR chat) to get other input. It often takes several weeks (or even longer) to get this right.
This will help to determine:
- whether the extension we need will have a single value (simple extension) or more than one value (complex extension).
- if this extension MUST be understood by the recipient – i.e. it changes the meaning of the resource making it clinically unsafe not to understand it, in which case it is a modifierExtension. eg the patient does NOT have this condition.
- If there is a specific set of values for the extension (more on that later)
And as part of the determining these requirements it is helpful to collect documentation for things like title, description, purpose, author, key words – things that we can record in the main part of the StructureDefinition that describe what it is intending to represent to a recipient, and to aid with discovery.
For the sake of this discussion, let’s assume that we want to be able to represent the age of the patient when some event occurred – say the age of the patient when a procedure was performed (“I had an appendicectomy as a child – don’t remember exactly when”). It is a simple extension (it will have only a single value), and can be ignored if the user doesn’t understand it.
Next, what is the context of our extension – which resources/s will it apply to, and whereabouts in those resources will it apply. Pretty much any part of a resource can be extended:
- We can add it to the resource root as a new element
- It can be added to a ‘backbone’ element (one that has child elements like Condition.stage)
- It can be added as an ‘extra’ to an existing element
In our example, we are wanting to represent the patients age when a procedure was performed. There is already a performed element, but it only has date and period. So we’ll add our extension to that element, with the context therefore being Procedure.performed Remember that multiple resources can use the same extension.
Next, we need to decide what datatype (or datatypes) are needed. From our requirements, we know that this information can come in a variety of different forms. It might be ‘aged 5’ or it might be ‘as a child’ so it sounds like both ‘string’ and ‘age’ are going to be needed.
(You could argue that if we have the age then we could calculate the date, but we might not want to do that as it would sound like we actually knew what the date was rather than guessing based on the age.)
We’ll also let the committee responsible for Procedure know that we’ve needed to do this with a suggestion that ‘Age’ be added as an option for performed – if they agree, then our extension won’t be needed in future releases.
Note that our extension can have any of the FHIR datatypes – including a reference to another resource.
Once we know what we want to represent, the next thing is to see if there is already an extension definition that does what we want so we can re-use it. Good places to look are in the spec itself (each resource has a list of the official extensions – see the ones for patient), in the Implementation Guides that have been published (e.g. US Core, previously known as DAF) and in Simplifier – a registry built by the good folk at furore.
In the longer term the simplifier registry will hopefully have a copy of most of the extension definitions that people have built so we’ll be able to just go straight there. There are a few enhancements (mostly around searching capabilities through the API) that need to be completed, but once that’s done then re-use should be simpler…
Assuming that we can’t find one to reuse, then we’re going to need to build our own so we’re going to need a unique URL for it. This is the url that a resource instance that has this extension will use to point to the definition as required by the specification.
The value of the Url will depend on a number of factors, so we will come back to that in a subsequent post. For now, assume we have an appropriate URL in a domain we control, or the domain owner has given one to us.
So now we know that we have to create an extension definition, where the extension will go in which resource/s, what datatype/s it can take and what the Url is. We’re almost there!
Except for a couple of things…
- If any of the data types are coded (code, Coding, CodeableConcept or Quantity) then we’ll need to create a ValueSet to hold the list of possible values, and figure out the binding strength (if a specific value MUST or SHOULD be in the ValueSet)
- If any of the data types are an Identifier, we’ll need to figure out the system from which the identifier should be drawn.
Both of these are a bit complicated, so for now we’ll just note that we have more work to do for these dataTypes. The next post will explore these in more detail.
With that proviso, we’re good to go. We have the information needed to build our extension definition and we know where to publish it to – the Url that we determined earlier.
(Actually, we don’t have to publish it there, it’s perfectly legitimate to just store it in a registry like simplifier, but it’s good practice to do so – then it is ‘resolvable’ – entering it into a browser will directly retrieve it. Actually, we should do both.)
The last thing we’ll think about in this post is how to actually create the StructureDefinition resource that is the extension definition. There are (at least) 3 options.
- We can create it manually in an XML or Json editor. Perfectly feasible, but hard to get right – under the hood it’s kinda complicated. (If you do go down this route, use Grahame’s server to help validate the resource. It’s not 100% perfect, but catches most of the syntactic errors. And have a look at some of the existing definitions).
- We can use the Forge tool from furore. This is the ‘official’ profiling tool for FHIR and by far the most comprehensive.
- clinFHIR can also create simple extension definitions. You have to create them directly against a FHIR server, and the functionality is not as comprehensive as Forge, but it is simpler to use (though, as the author, I am biased!)
So that covers the overall flow of creating an Extension Definition (at least one way of doing it). There were 2 topics we put aside:
- Determining the Url of the Extension Definition
- Extra work needed for coded types and identifiers.
We’ll come back to those in the next post.
Other posts in this series: