Profiling FHIR in DSTU-2

As we mentioned in the previous post, profiles have changed significantly in the next DSTU.

Profiling is a really important part of FHIR. The resource themselves are designed to be quite generic ‘building blocks’ that can be used in many different contexts. If you take a look at one, you’ll notice that almost all of the properties are optional and even where coded properties have Terminologies assigned to them, these are often quite ‘loose’ and designed to be amended by a Profile

Read more of this post

A simple FHIR extension viewer

One of the big changes that occurred in the DSTU-2 candidate was that the profiling mechanism has been substantially improved (albeit a bit more complicated than it was). In particular, extension definitions have been moved out of the profile resource, and are now a specific resource in their own right, which allows better re-use.

We’ll take a deeper look at extensionDefinitions and Profiles in a little while (they are also a topic in the next connectathon), but I thought I’d share a simple tool I wrote to help locate and visualize the ones that are being developed at the moment. You can view the tool here.

It retrieves all the definitions from the specification, and then lists them in a number of different ways (by name, by resource, by context) with some basic searching/filtering. You can select a definition, and then visualize it either as JSON or XML, as well as a simple text view.

A couple of notes:

  • It retrieves the definitions using this call: http://hl7.org/implement/standards/FHIR-Develop/extension-definitions.json. It would be better to load them directly from a FHIR server, but the build process is not currently loading them properly. I’ll adapt it what that is corrected.
  • As it loads all the definitions from a single source into memory, it won’t scale at all well – but then, I suspect it’ll be redundant before that is a problem.
  • I wrote it to run in Chrome. It should run in any recent browser, but no guarantees…
  • This is not a production level app and may/will break! Let me know if so and I’ll figure out what went wrong. No specific SLA though…

You’ll also appreciate why I haven’t attempted a new career as a web developer 🙂

I intend to enhance it as time goes on, specifically adding profiles and possibly basic editing but any suggestions and/or bug reports) are welcome!

Merry Christmas to you all!

 

 

 

 

Profiling a FHIR Careplan for Immunizations

After the previous discussion on how to represent an Immunization plan, I had intended to talk about how to represent the Immunization protocol (or schedule), and how to apply that to a patients’ plan, but (as so often happens) I got a bit side-tracked, and thought we could first think about how we might create a Profile against the CarePlan resource to represent an immunization plan.

Now, we’ve talked about FHIR profiles before so I’m not going to repeat that here, other than to say that it is the profile that takes a standard resource (or resources) and makes them fit more precisely to a particular Use Case of some sort, so profiling CarePlan to support an Immunization plan seems a perfect fit!

There’s actually quite a lot to do to get a good profile (and I’m sure I haven’t got it completely correct), but at a high level, once you have your use cases you go through the resource and:

  • Alter multiplicity of elements (e.g. to make an optional element required or not used. Remember you can’t make a required element optional though)
  • Specify a particular terminology or codeset for a binding (and often you’ll define a ValueSet to hold the list of allowable codes)
  • Add a new element (as an extension) where it’s needed by the Use Case but not defined in the base resource

(There’s other things you can do as well, but that’s enough for our current needs).

Overall design

Here’s the structure of the Care Plan resource (Sorry about the image quality – its a screen scraping from my computer – here’s the original)

Screen Shot 2014-05-27 at 1.48.31 pm

How we’ll structure our profile overall is to use the goal element to list the diseases that this plan is intended to protect against (using an extension), then optionally link the activities back to the goals/diseases that are covered by that vaccine. That way we can say which activities contribute to protection against which disease. We’ll make this all optional, as not everyone will want to go to this level of detail (and, in truth, is probably a bit overkill). (btw – Another way of doing the same thing would be to add extensions to the activity directly to indicate the diseases being covered)

The activity will generally be the administration of a vaccine, however we’ll keep it a bit flexible to allow for, say, educational sessions as part of the plan. We’ll know which activity is an vaccination because the activity.simple.category will have the value ‘drug’.

We only need to profile the CarePlan resource for this Use Case.

For simplicity, we’ll put all the extensions in the same profile – in real life we might try to re-use existing extensions or to make some of ours a bit more general. This will really need common registries of profiles, which the FHIR team are working on at the moment…

Layout

So the following section lists the changes (in a textual format) that we’ve going to make to the CarePlan resource to allow it to hold the information required to represent an immunization plan. Each entry has the path to the element, followed by the multiplicity (which may not be the same as that in the base resource). If the entry is an extension (and remember that extensions can be at any level in a resource) then the path will end in a #{extensionDef code} and the data type will be displayed. Thus:

Careplan.goal#disease (0..1) CodeableConcept

means that this extension is against the goal element of the CarePlan resource, that it’s optional and there can only be one, and that the datatype is CodeableConcept.

If the values of the element (extension or base element) come from a ValueSet, then we’ll place the name of the ValueSet in square brackets at the end. Eg

Careplan.Activity.simple.code (1..1) [immunizationVaccines]

means that the value of the code (which is required in this profile) comes from the valueset whose name is immunizationVaccines. (Actually, this should really be a complete URI, but we’ll keep it simple to avoid cluttering the page). Note that this layout is just the one we’re using for this post – the formal representation will be the profile resource and maybe other artifacts that the core team is working on.  (Actually, I think the next connectathon is going to focus on profiles and conformance)

So, here we go. To minimize space, we’ll only include entries that are different to the base resource, or where there’s a particular comment to make.

We’ll also do this in 2 posts. This one will be more of a ‘design’ session – what we’re going to do and why. The next post will build the actual profile.

Items in the Profile

Careplan#protocolDescription (0..1) string

An extension where we can describe the protocol that this plan was drawn from.

Careplan#protocolUri (0..1) uri

A direct link to the protocol (if known).

CarePlan.patient (1..1)

You have to have a patient in our plan…

Careplan.patient#dob (0..1) date

The patients Date of Birth. This is a bit naughty as you should really retrieve the Patient resource and look up the Date of Birth from there. The reason to include it here as an extension is to allow us to be able to determine if an immunization is overdue just on the information in the plan. In reality, you probably woudn’t do this but, hey, its my blog and I’ll de-normalise if I want to

Careplan.period (0..1)

This would be the age range over which the immunization plan was active – eg from birth to 18 years

Careplan.modified (1..1)

This should be updated when the plan itself is changed – ie a new activity is added, to the status of an existing activity changed. The multiplicity is changed to make it required.

Careplan.concern (0..0)

As this plan is specifically about immunizations, the concern is not needed – i.e. the whole point is to avoid the patient getting those conditions. Change the multiplicity to 0..0 to remove it.

Careplan.goal#disease (0..1) codeableconcept

We’ll use the goal to list the diseases that this plan is intended to protect against, then optionally link the activities back to the goal. That way we can say which activities (immunizations) are protecting against which diseases. Note that there’s only a single disease per goal, but multiple goals per plan.

Careplan.goal.status (0..0)

The overall status of the plan is at the careplan level, not the goal.

Careplan.goal.concern (0..0)

Same notes as for careplan.concern.

Careplan.Activity#immunization (0..1) ResourceReference

An extension that references the Immunization reference. Should be populated when the vaccine is either given or offered and declined.

Careplan.Activity.goal (0..*)

To allow us to link this activity back to the goals (the diseases this vaccination is intended to protect against) if we want to.

Careplan.Activity.status (0..1)

Really the only codes that makes sense here are ‘completed’ and ‘cancelled’. However, this is a fixed code set in FHIR so we can’t change it. If due then we can either leave it blank, or we could use the value ‘not started’ or ‘scheduled’

Careplan.Activity.actionResulting (0..0)

Don’t want to record this in the plan

Careplan.Activity.detail (0..0)

The careplan.activity.notes can capture the level of detail that may be required, so this is not required.

Careplan.Activity.simple.category (1..1)

Fix the value as ‘drug’. We might want to suggest that ‘immunization’ be added as an option to the base resource.

Careplan.Activity.simple.code (1..1) [immunizationVaccines]

This will be the vaccine that is to be given so is mandatory. The value is drawn from the immunizationVaccines ValueSet

Careplan.Activity.simple.code#numberOfDoses (0..1) integer

The number of doses of this vaccine that are going to be given altogether

Careplan.Activity.simple.code#doseSequence (0..1) integer

The sequence number for this dose

Careplan.Activity.simple.timing (1..1) Period

Fix to use a period and make required. The ‘start’ property is required. ‘end’ is optional. This will be the period over which the vaccine must be given to be effective.

Careplan.Activity.simple.location (0..0)

No need to specify location in the plan

Careplan.Activity.Simple.product (0..0)

This information is in the code

Careplan.Activity.simple.dailyAmount (0..0)

 Not needed

Careplan.Activity.simple.quantity (0..0)

Not needed

So now that we have an idea about what our profile is going to look like, we can build the profile itself. That will be the topic of the next post!

 

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.

FHIR Profile Videos

Rene just sent this note to the FHIR list with some videos on profiles that Ewout has done:

FYI: The ‘advanced’ FHIR profiling video (profiling extensions and slicing) can be found at https://vimeo.com/88235048 , the ‘introduction to profiling’ video (which was released a while ago) can still be found at https://vimeo.com/87074652 . Both are presented by Ewout Kramer.

So I don’t loose them…

Profiles and ValueSets in FHIR

I’ve been meaning to talk about Profiles and ValueSets for a little while now. They’ve come up from time to time in this blog – this post was a comment from Grahame about the use of Profiles for specific Use Cases, and we’ve have a number of discussions about extensions such as this one which are defined in profiles.

Profiles are actually a ‘big thing’ for FHIR. You can think of the base FHIR structures (Resources, Extensions, Bundles, Tags, Queries etc.) as the common building blocks that you can use to build a solution – the Profile is where you can say how these blocks are used in your particular application – and what are the extra data items (represented as extensions) that you need.  And this can be both computable and as documentation for humans.

Update: Rene Spronk has commented about a video tutorial given by Ewout Kramer that can be found here. This gives a nice overview of profiles and is well worth a read…

Before we get into too much detail, lets talk about a couple of related resources – Conformance and ValueSet.

Conformance

The Conformance resource is used to describe the capabilities of a particular server. This can either be about an actual server (it can be downloaded by a query to the server root like this: http://fhir.healthintersections.com.au/open/metadata – or using the OPTIONS verb) or it can be used when creating specifications for a server – what a client expects a server to be able to do.

As well as specifying the ‘standard’ resources and queries, the conformance resource can reference the profiles that it supports.

Suppose, for example, that we defined a profile for an antenatal visit. The profile might specify:

  • a particular Questionnaire resource (questionnaire.name / questionnaire.identifier)
  • that the questionnaire author must be a Practitioner
  • that the subject is required and so forth

(we’ll talk about how to do this later). We’ll give this profile an identifier that we’ll call ‘antenatal’ in this post.

A server that supported this profile – i.e. it could check that a particular questionnaire had the right identifier, has a subject and a Practitioner author etc. would then add this profile to its conformance statement – if it receives a questionnaire claiming to conform to the antenatal profile, then the server can check that it does – rejecting it if not (and ideally including an OperationOutcome in its response to say why it failed.) Actually – to be correct the spec doesn’t state that the resource should be rejected – that’s up to the implementation to decide.

Now suppose that we have a client application that can create a questionnaire that conforms to this profile. All it needs to do is to POST the questionnaire to the servers Questionnaire endpoint, including a profile tag HTTP Header in the request that contains the antenatal profile. The server recognizes the tag, loads the profile and checks that the submitted resource does, in fact, meet the requirements of the profile. (Again, the details of this are up to the implementation)

In this way, the server can apply business level validation to resources to ensure compliance with business rules.

Finally, a single server can support multiple profiles (Indeed, a single resource could also be compliant with multiple profiles).

ValueSet

A ValueSet is simply a set of codes. It is used where you want to specify that the value for a particular code in a resource is drawn from a pre-defined set of codes. (It can get quite  a lot more complex than that of course, but that description will do for now)

For example, suppose we are recording medicationAdministrations, and want to be able to indicate whether a particular administration was given on time, was early or was late. MedicationAdministration does not have this property so we create an extension definition (in a profile) to represent it. We actually have 2 steps to do in setting this up.

  • First, we create the ValueSet resource. In this case we’ll define the values directly in the ValueSet (we could also refer terminologies like SNOMED or LOINC if that were appropriate) and give it an appropriate identifier. Here is what it might look like
<ValueSet xmlns="http://hl7.org/fhir">
     <identifier value="onTimeOrNot"/>
     <name value="medsontime"/>
     <description value="Were medications given on time"/>
     <status value="draft"/>
     <!-- Define the  options in the resource rather than an external terminology-->
     <define>
         <system value="http://fhir.orionhealth.com/fhir/ns/onTimeOrNot"/>
         <concept>
             <code value='early'/>
             <display value="Early"/>
             <definition value="The medication was given early"/>
         </concept>
         <concept>
             <code value='on-time'/>
             <display value="Early"/>
             <definition value="The medication was given on time"/>
         </concept>
         <concept>
             <code value='ate'/>
             <display value="Late"/>
             <definition value="The medication was given late"/>
         </concept>
     </define>
 </ValueSet>

  • Next we create a profile with an ID of ‘medadmin’ (so we can easily refer to it in a URL) and in that profile we’ll create an extension definition (ExtensionDef). We’ll give the extension a code of ‘onTimeOrNot’. In the definition of the extension we indicate that the datatype of the extension is a code, and that the value of this code must come from the ValueSet we just created (this is called a binding) – by including a reference to the ValueSet in the extensionDef element. Here’s an example (assuming that the ID of the ValueSet was 100):
<extensionDefn>
     <code value="onTimeOrNot"></code>
     <contextType value="resource"/>
     <context value="MedicationAdministration"/>
     <definition>
         <short value="Was the medication given on time"/>
         <formal value="Was the medication given on time"/>
         <min value="0"/>
         <max value="1"/>
         <type>
             <code value="code"/>
         </type>
         <isModifier value="false"/>
         <binding>
             <name value="Set of coded values"/>
             <isExtensible value="false"/>
             <referenceResource>
                 <reference value= "http://fhir.orionhealth.com/fhir/ValueSet/100"/>
             </referenceResource>
         </binding>
     </definition>
 </extensionDefn>

Both resources get saved on our (or someone else’s) server.

When we want to create a MedicationAdministration resource that can record whether the medication was given on time, we simply include an extension in the resource like so:

<extension>
  <url value = 'http://myserver/profiles/medadmin#onTimeOrNot'/>
  <valueCode value = 'early'/>
</extension>

(If we need to, we can GET the profile, then GET the ValueSet to display a list to the user – though we’ll often have that in our application anyway).

If a recipient receives our resource and doesn’t know what ‘onTimeOrNot’ means, they can follow the url to the Profile which will describe the extension, and to the ValueSet which has the options. Of course, as this was an ‘ordinary’ extension we can safely ignore it if we don’t understand it – had it been a modifierExtension then it wouldn’t have been safe to do so.

The following diagram shows the relationships between these resources and note that they are all ‘instance’ resources with a ID – an fact the Profile & ValueSet resources could form the basis for a registry…

profile-1 (1)

Profile

So we’re now ready to start talking about the Profile – and we’ve pretty much used up the space. Just a summary then, and the next post will go into more detail.

  • The profile is how you ‘constrain’ one or more resources to meet your particular Use Case.
  • It is also where you define the extensions you are going to need (and you almost certainly will need some).
  • You can also define custom queries here
  • It contains both computable artifacts and human documentation.
  • It can get complex! – for example one profile can refer to another

One last thing to point out is what profiles can’t do, and that is to change a resource in such a way that a recipient must understand the profile to safely process the resource. This is an absolute no-no in FHIR. For example, you can’t specify a default in a profile, or require the recipient to download the profile before processing.

If you do need to specify something that must be understood then create an extension setting the ‘isModifier’ to true. A resource instance will use the modifierExtension element to hold this data – and a FHIR recipient must always understand modifierExtensions to safely process resources.