FHIR Profiles: an overview

I’ve been spending a lot of time recently looking at Profiles (we’re building a tool to help manage the ones we’re creating at the moment).

As we start to implement FHIR interfaces in real systems, we’ve come to appreciate just how important profiles are going to be. The reason  is that FHIR is essentially a set of basic building blocks (health-IT lego if you will) and some rules around how to manipulate them. The specification is deliberately very flexible to allow the blocks to be used in lots of different scenarios, both in terms of interoperability paradigms (document, message, REST, service) but also in different countries that can have vastly different requirements in terms of content, terminology, privacy and the like.

Furthermore, and again by very deliberate design, the ‘core’ contents of resources are limited to those elements that are currently being used by most implementers world-wide. This is to keep them manageably sized – the so-called ‘80%’ rule (which, unfortunately, has caused a lot of confusion as my colleague Edward has complained about). From a FHIR perspective there is no difference between core and extension properties – it’s just that the core properties are more common. (Perhaps we should have called extensions ‘special’ elements rather than ‘extensions’…)

What all this means is that in practice when you start to use FHIR for real, you’re likely going to need to adapt the resources to suit your own requirements, and that is where profiles come in.

A sample process might be:

  • Start with a set of requirements (Use cases, user stories, story boards etc).
  • Define the behaviours and the data models you’re going to need. (Behaviours – e.g. queries, workflow, updates, services etc. are outside the scope of this post – but you’d document them in the Conformance resource).
  • Once you have the data model (and these may be in a form like openEHR archetypes – or just a simple table), you then need to map these to the FHIR resources. It’s at this point that you’ll likely find:
    • There are some things you want to exchange that aren’t in the current resources
    • The resources have elements that you don’t want to use.
    • You will want to be more specific about some aspects of the resource – e.g. use a specific terminology for an element, or make an element required rather than optional
    • There might even be models for which no resource can be found. Again this is a bit outside the scope of what we’re talking about here – an option is to use the Other resource (originally known as the resource-with-no-name) and define everything as extensions in a profile.

It’s the profile that allows you to define these differences in a way that the people with whom you are interoperating can understand what you’re trying to say.

So what can you do with a profile? Broadly there are 2 things that you use them for:

  • Adapting the core resource structures to meet your requirements
  • Defining extensions on resources – extra properties needed for your use case.

And there’s a third category – metadata. Metadata is all about describing what the purpose of the profile is (what requirements it fulfils) and discoverability.

  • If we are a server then a client can read our conformance resource, which will list the profiles we support (and provide a link to them).
  • If we are a client, we can tell a server that we conform to a profile (the server will probably still check).
  • If we receive a resource with an extension we don’t recognise, it will point to the profile in which it is described so we can decide what to do with it.

It’s important to appreciate that a single resource instance can have extensions from many different profiles, hosted by many different servers (a profile is just a resource after all – anyone can store them). And also important to appreciate that a profile cannot change the definition of a resource in such a way that it cannot be processed without referring to the Profile – this is the reason behind some of the thing you can’t do with profiles.

And when you design – and use – profiles, you really need to be thinking about re-usability – as Lloyd commented on the previous post, it’s better to have a generic profile/extension that can be used in multiple places than a specific extension that can only be used in one. Or even better, use one that someone else has defined – discoverability of ‘prior art’ is something that we really need to work on, which will be facilitated by the availability of public registries for profiles, and better searching – codes, tags – that sort of thing.

Anyway, on with some more detail on Profiles.

Adapting the core resource structure

Each element in a resource can have a number of characteristics

  • Its name
  • One or more datatypes
  • Multiplicity (how many there can be in a resource)
  • Possibly a binding to a terminology (which may or may not be defined in the spec)

Apart from the element name, the Profile can be used to constrain any of these characteristics – within limits. The following sections describe the most common things you might want to use a profile for.

DataType

You can specify that for your Use Case, the datatype must be a specified sub-set (or just one) of those defined. For example, Observation.subject can be a Patient, Group, Device or a Location, but in your use case, it might only make sense to be a Patient. Note that you cannot specify a datatype that is not already one of the options (or a recipient that didn’t know about your profile wouldn’t know what to do).

Multiplicity

The following table shows how you can alter the multiplicity, with the rows being the multiplicity in the spec and each column being a multiplicity you can specify in the Profile.

0..0
(Not used)
0..1
(optional)
0..n
(optional, many)
1..1
(required)
1..n
(at least 1)
0..1 yes yes no yes no
0..* yes yes yes yes yes
1..1 no no no yes no
1..* no no no yes yes

In summary:

        • If it’s already optional then you can make it required or not used.
        • If it’s already required then you can’t make it optional
        • If more than one is allowed, then you can restrict the number (this is called ‘slicing’ – refer to the spec for details)
        • If only 1 is specified, then you can’t make it many.

The following snippet shows how we’ve restricted the datatype of ‘asNeeded’ in the MedicationPrescription resource to Boolean, and also made it required, by setting both min and max to 1.

<structure>
    <type value="MedicationPrescription"/>
    <name value="asNeededConstraint"/>
    <element>
        <path value="MedicationPrescription.dosageInstruction.asNeeded"/>
        <definition>
            <short value="Only support boolean in the 'asNeeded' property"/>
            <formal value="Only support boolean in the 'asNeeded' property"/>
            <min value="1"/>
            <max value="1"/>
            <type>
                <code value="boolean"></code>
            </type>
            <isModifier value="true"/>
        </definition>
    </element>
</structure>

Terminology

Many of the elements can refer to a code-set, a terminology or a ValueSet. These elements generally have the datatype of coding or codeableConcept. In most cases the spec doesn’t say which terminology to use (though there will often be examples or recommendations). You can use a Profile to specify a terminology or ValueSet you want to use.

(Note that the code datatype is generally bound to a fixed set of values than cannot be altered in a Profile. These are reserved for elements that are generally used in workflow scenarios – ‘status’ elements are the most common).

The following snippet shows how we’ve restricted the code values that can be used for medications to those defined in a ValueSet of ULM (Universal List of Medicines) codes that a GP (Ambulatory care) clinician can prescribe. We could also have used a direct reference rather than the  ValueSet, but the ValueSet allows us to filter the list.

<structure>
    <type value="Medication"/>
    <name value="medicationCodeConstraint"/>
    <element>
        <path value="Medication.code"/>
        <definition>
            <short value="GP ULM Codes only"/>
            <formal value="Specify that the medication code must come from the NZ ULM codeset"/>
            <min value="0"/>
            <max value="1"/>
            <isModifier value="false"/>
            <binding>
                <name value="List of medications GP's can prescribe"/>
                <isExtensible value="false"/>
                <referenceResource>
                    <reference value="http://www.nzgovt/fhir/ValueSet/ulm-gp"/>
                </referenceResource>
            </binding>
        </definition>
    </element>
</structure>

Default Values

You can’t set a default value. The reason for this is that if you could, then it wouldn’t be safe to process a resource without referring to the Profile – which would severely impact on usability.

Extensions

As we’ve discussed previously, we use extensions where we have some data that we wish to exchange that is not currently in the FHIR resource.  We’ve talked about extensions before and made some notes about them when thinking about code sets, so we won’t go over that again but everything that you can do to a structure (core element) you can do with an extension – in fact much of the definition in the profile is the same for both.

Last Word

As I hope you agree, the profile is an important resource to get your head around – and to use. When the public registries become available, re-use of profiles and extensions is going to become a lot easier – but in the mean time you can practise using Grahames  or Ewouts server.

And remember that the enforcing of the constraints described in the profile is completely up to you. FHIR gives you the mechanics to describe these constraints in and easy to use, computable way. It’s up to you to adhere to / validate those constraints.

About David Hay
I'm a Product Strategist at Orion Health, Chair emeritus of HL7 New Zealand and co-Chair of the FHIR Management Group. I have a keen interest in health IT, especially health interoperability with HL7 and the new FHIR standard.

8 Responses to FHIR Profiles: an overview

  1. Diego B. says:

    So which one is the formal representation of a profile? Is the XML with the HTML code embedded?

    • david hay says:

      Hi Diego – the profile is a standard FHIR resource (you can follow the link in the post to the specification) so can be in XML or JSON. In the post the XML snippets were parts of a profile to illustrate a point. I’m not sure what you mean by ’embedded HTML’. All resources have an HTML narrative which should include a human readable representation of what the resource states – was that your question?
      cheers…

      • Diego B. says:

        More or less, the question at the end is that you have both a XML snippet and a HTML narrative… which is the one considered ‘correct’? I suppose that for the profiles part of the specifications you can say both, but what about the extensions?

  2. David Hay says:

    Sorry, still not quite understanding the question. The profile contains the definition of the extensions in a structured format for a computer to read (I didn’t put a snippet in here as I did so here: https://fhirblog.com/2014/03/25/extending-fixed-code-sets-revisited/ ). A single profile could contain both structure and extensionDefns, and the HTML narrative would be the human description of both. So the word ‘correct’ doesn’t really apply – the structured and the narrative should say the same things to different audiences…

    • Diego B. says:

      Yes, but in case they contain contradicting information, which one is the correct one? e.g. in a CDA document you can have both, but the narrative is the one supposed correct.

      • In a FHIR document or any other situation where you have formal authentication of a particular resource, what is authenticated is the narrative. (For a document, it’s a specific combination of the narratives of a subset of the resources in the document, as defined in the spec.) However, in terms of profile, if you’re asking what really counts, I would say the discrete data because that’s what will be used to generate code, perform validation, etc.

        In general, the narrative is authoritative for humans, the computable content is authoritative for devices.

      • Diego B. says:

        I still think that this should be clarified in the norm itself, Lloyd. Do you think we should discuss this on the FHIR mailing list?

      • Feel free to raise a tracker item :>

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: