Extending fixed code sets – revisited

We’ve talked previously about the options available when you are building a FHIR interface (a façade) to an existing system, and there is a resource property with a fixed code set whose values are not the same as the ones in the existing system.

One of the options we discussed was to map the codes in the existing system to those in the spec, using extensions where existing codes ‘meant’ the same – just added more detail.

For example – in our existing system we have the concept of ‘for review’ prescriptions – the prescription has been issued, but local policy dictates that the prescription must be reviewed by a pharmacist (perhaps this must occur if the patient is on many medications) so it is not yet ready for dispensing/administration.

The MedicationPrescription.status field has ‘on hold’ as one of its values which is close enough for us to use. After all, a MedicationPrescription in a ‘for review’ status is, effectively on hold until the pharmacist has approved it (or not – as the case may be).

So we have a solution – but we are losing some data. Clients that only understand the spec won’t be affected, but clients that are familiar with our existing system (like the one we’re building) could use that in the display to give the user more information.

So, let’s build an extension.

Remember that there are 2 parts to an extension:

  •        It is defined in a Profile (in the <extensionDefn> element)
  •        It is used in an instance using the <extension> element (or <modifierExtension> if it modifies the meaning.

So we have a few decisions to make.

First, is this a modifierExtension? Well, we’ve already determined that it is safe to represent a MedicationPrescription in the status of ‘for review’ as if it were in the status of ‘on hold’, so it can be an ordinary extension (which is a relief – modifierExtensions are to be avoided if possible).

Next, what’s the scope of this extension? What resources can it be applied to, and does it only apply to specific properties of that/those resource/s? I suspect that this is always going to be a bit more of an art than a science – ideally we want to have reusable extensions (and I have a post planned on that), but we do need to be careful that it ‘makes sense’ to do so.

In this case, we’re going to assume that ‘for review’ really only makes sense for a MedicationPrescription, and further that it only makes sense to use it in the MedicationPrescription.status property (after all – a ‘reason for prescription’ of ‘on hold’ doesn’t make a lot of sense).

So, now that we’re got an extension scoped to a single property of an instance of MedicationPrescription, how are we going to represent that in the instance? And what will the definition look like in the profile?

I find it easier to start with the instance.

Recall that an extension in an instance can apply:

  •        to the whole instance (in which case it is at the top of the instance)
  •        to a specific property (in which case it is represented with the property)
  •        or to a datatype (in which case it is represented with the value)

Clearly this is the second option – the extension will be with the property.

So instead of:

&lt;status value=&quot;on hold&quot;/&gt;

we will have

&lt;status value=&quot;on hold&quot;&gt;
  &lt;extension url=&quot;wwww.fhir.orionhealth.com/Profile/nma#original-code&quot;&gt;
    &lt;valueCode value='for review'/&gt;
  &lt;/extension&gt;
&lt;/status&gt;

Not too hard! Note the url in the extension:

  •        the extension is defined in the Profile to be found at wwww.fhir.orionhealth.com/Profile/nma
  •        it has the name of ‘original-code’
  •        it is of the datatype ‘code’.

Now for the definition.

We’ve already decided on the Profile and the name of the extension – how do we define it (including the set of possible values) – and, in particular, how do we state that it should only be used for the MedicationPrescription.status property?

Well, to define the set of possible values we create a ValueSet that defines the codes (they will almost certainly be in our own local system) and then create a binding to that valueset from the extensionDefn element in Profile

To indicate that the extension should only be used by the MedicationPrescription.status property, we simply set the value of extensionDefn.contextType to resource, and the context value to MedicationPrescription.status property.

So the complete definition will look like this:

&lt;extensionDefn&gt;
    &lt;code value=&quot;original-code&quot;/&gt;
    &lt;contextType value=&quot;resource&quot;/&gt;
    &lt;context value=&quot;MedicationPrescription.status&quot;/&gt;
    &lt;definition&gt;
        &lt;short value=&quot;Detailed status codes used by the HIS&quot;/&gt;
        &lt;formal value=&quot;These are the mode detailed codes used by the HIS system for MedicationPrescription status and mapped to the standard codes.&quot;/&gt;
        &lt;min value=&quot;0&quot;/&gt;
        &lt;max value=&quot;1&quot;/&gt;
        &lt;isModifier value=&quot;false&quot;/&gt;
        &lt;binding&gt;
            &lt;name value=&quot;Valid values for original code&quot;/&gt;
            &lt;isExtensible value=&quot;false&quot;/&gt;
            &lt;referenceResource&gt;
                &lt;reference value=&quot;ValueSet/nmaStatusCodes&quot;/&gt;
            &lt;/referenceResource&gt;
        &lt;/binding&gt;
    &lt;/definition&gt;
&lt;/extensionDefn&gt;

One thing we haven’t done is to define the actual mappings between the two code systems – that will be up to the application to do so. However, there is a proposed resource – the concept  map – that we could use for this, which would make the mappings explicit. And incidentally, this is one of the reasons that we created the ValueSet as a separate resource, rather than just containing it in the profile. Containing resource seems easier, but does significantly reduce options downstream so should only be done when there are no other options.

So, we’re good to go!

 

 

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
&lt;ValueSet xmlns=&quot;http://hl7.org/fhir&quot;&gt;
     &lt;identifier value=&quot;onTimeOrNot&quot;/&gt;
     &lt;name value=&quot;medsontime&quot;/&gt;
     &lt;description value=&quot;Were medications given on time&quot;/&gt;
     &lt;status value=&quot;draft&quot;/&gt;
     &lt;!-- Define the  options in the resource rather than an external terminology--&gt;
     &lt;define&gt;
         &lt;system value=&quot;http://fhir.orionhealth.com/fhir/ns/onTimeOrNot&quot;/&gt;
         &lt;concept&gt;
             &lt;code value='early'/&gt;
             &lt;display value=&quot;Early&quot;/&gt;
             &lt;definition value=&quot;The medication was given early&quot;/&gt;
         &lt;/concept&gt;
         &lt;concept&gt;
             &lt;code value='on-time'/&gt;
             &lt;display value=&quot;Early&quot;/&gt;
             &lt;definition value=&quot;The medication was given on time&quot;/&gt;
         &lt;/concept&gt;
         &lt;concept&gt;
             &lt;code value='ate'/&gt;
             &lt;display value=&quot;Late&quot;/&gt;
             &lt;definition value=&quot;The medication was given late&quot;/&gt;
         &lt;/concept&gt;
     &lt;/define&gt;
 &lt;/ValueSet&gt;

  • 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):
&lt;extensionDefn&gt;
     &lt;code value=&quot;onTimeOrNot&quot;&gt;&lt;/code&gt;
     &lt;contextType value=&quot;resource&quot;/&gt;
     &lt;context value=&quot;MedicationAdministration&quot;/&gt;
     &lt;definition&gt;
         &lt;short value=&quot;Was the medication given on time&quot;/&gt;
         &lt;formal value=&quot;Was the medication given on time&quot;/&gt;
         &lt;min value=&quot;0&quot;/&gt;
         &lt;max value=&quot;1&quot;/&gt;
         &lt;type&gt;
             &lt;code value=&quot;code&quot;/&gt;
         &lt;/type&gt;
         &lt;isModifier value=&quot;false&quot;/&gt;
         &lt;binding&gt;
             &lt;name value=&quot;Set of coded values&quot;/&gt;
             &lt;isExtensible value=&quot;false&quot;/&gt;
             &lt;referenceResource&gt;
                 &lt;reference value= &quot;http://fhir.orionhealth.com/fhir/ValueSet/100&quot;/&gt;
             &lt;/referenceResource&gt;
         &lt;/binding&gt;
     &lt;/definition&gt;
 &lt;/extensionDefn&gt;

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:

&lt;extension&gt;
  &lt;url value = 'http://myserver/profiles/medadmin#onTimeOrNot'/&gt;
  &lt;valueCode value = 'early'/&gt;
&lt;/extension&gt;

(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.

FHIR resources in specific scenarios

Taking the example of Grahames ‘Q&A’ format, the following question was asked on the FHIR List forum:

Based on what I have seen, FHIR defines a set of resources and all possible relationships between resources, but doesn’t define which/how resources should be used in a particular scenario – the latter needs to be defined as a Profile. And FHIR per se doesn’t have Profile recommendations for any scenario. Implementers need to define their own Profiles and figure out how systems interoperate on a semantics level. 

and answered by Lloyd:

Sort of.  First, FHIR doesn’t actually define all possible relationships between resources.  It merely defines the “common” ones – those deemed to be within the 80%.  Many other types of relationships are possible through the use of extensions.  (E.g. encounter is associated with a single patient in the core resource, but with extensions could support multi-patient “group” encounters, for example)
 
You can approach interoperability with FHIR in a couple of ways.  In one approach, you just expose everything you do as a FHIR resource and anyone who wants to consume your content can simply pick and choose from what you expose (whether as a dump in a bundle or by hitting your FHIR REStful service).  In the second approach, you expose a particular subset of content (or perhaps even enhance the capability of your system to support additional data elements) as defined by a particular profile on FHIR.  These profiles could be created by a variety of groups.  Some (e.g. a FHIR equivalent of CCDA) will likely be created by HL7 international.  Some may be produced by IHE or other international SDOs.  Some will be created by HL7 affiliates and national programs.  Some will be created by large healthcare organizations.
 
The creation of profiles will take time and will be driven by specific use-cases.  They don’t yet exist.  So for early adopters, you sort of have to either take the first approach or go through the process of creating your own profile, ideally with a group of like-minded early adopters.  If you’re taking the second approach, you need to identify the area of healthcare that you’re targeting, look at existing capabilities and business needs.  Inpatient care and Outpatient care look quite different.  (So does human vs. veterinary or individual vs. public health.)  That’s why your initial question of identifying the “minimum” is so challenging to answer.  The minimum depends very much on what area of healthcare you’re targeting, what problem you’re trying to solve and even what country/region you’ll be working in.

I thought it was worth sticking it up here so I can find it later! Profiles are going to be important…

The FHIR DocumentReference resource

In the previous FHIR-XDS post we discussed how a document source actor (ie a system that creates a document) could create a document and DocumentReference resource and send them to the Repository server. (Actually, we described a couple of ways that this could be done – and there are a few subtleties yet to discuss about server behaviour – but we’ll hold that for later).

However, we didn’t have a lot of time to talk about the DocumentReference resource itself. This resource represents the metadata about the document and allows a consumer to search the registry (or any server hosting these resources) to retrieve matching documents. From these results, a consumer can then generate a list of documents so that a consumer can select one to view.

The documents themselves can be of any allowed type (CDA, PDF, FHIR document, text etc) and can be stored on any server accessible via HTTP – and they do not need to be FHIR servers. It is quite legitimate for a DocumentReference resource to refer to a static document on any server (or, for that matter, a URL that generates a document ‘on the fly’, though you’d want some way to persist the generated document for medico-legal reasons as described in the ‘IHE on-demand document‘ profile). And, if one is being particularly pedantic, then even HTTP is not really required – you could use FTP or any other supported protocol.

It is important to note that although the DocumentReference resource was developed to support some of the requirements of an XDS infrastructure, it is not restricted to that purpose and can be used in any situation where the business requirement is to create a ‘list of available documents’, from which one or more can be chosen for viewing.

In fact, the FHIR specification defines a specific XDS profile that describes how the DocumentReference resource is to be used in the context of an XDS installation – for example some fields that are optional in the resource, are required when acting as a proxy to XDS. The link also gives guidance for mapping between XDS and FHIR elements, including fields required for XDS that are not in the DocumentReference and so represented by extensions.

The following description refers to the generic DocumentReference resource. Note that there are a number of properties whose value should come from a ValueSet defined by the governance body that oversees the overall installation (an Affinity Domain in XDS-speak – though the affinity domain covers much more than just code sets). We will talk a bit more about ValueSet’s after this list.

  • The masterIdentifier is the identifier of the document as created by the source. It is version specific – i.e. a new one is required if the document is updated (We’ll talk about updating documents in a separate post).
  • There can be any number of other document identifiers that make sense. For example, there might be a version independent identifier here.
  • The subject is who the document is about. Generally this is a patient, but the specification also supports a Practitioner, a Group or a Device.
  • The type and class indicate what kind of document this is- (eg a discharge summary). A ValueSet should be defined for each. (Note that ‘class’ has been called ‘sub-type’ in some versions of this resource)
  • There is at least one author, which is a Practitioner.
  • There can be an Organization which is the custodian of the document – responsible for maintaining the document
  • There’s a policyManager link to a URL that describes the access policies to the document.
  • The authenticator of the document can be an Organization or a Practitioner.
  • The created date is when the document was created (not necessarily related to the period of the service that the document may describe – this is in the context.period element).
  • The indexed date which is when the DocumentReference resource was created.
  • The status allows minimal workflow of this DocumentReference resource (NOT the underlying document). Options are current, superseded or error. We’ll talk more about this status when we talk about updating a document in a later post.
  • The docStatus and supercedes allow a document to be updated (superseded) or otherwise have it’s status changed. This is a CodeableConcept, and so can accommodate a specific workflow defined by the affinity domain such as preliminary, final, amended or whatever, as documented in the ValueSet.
  • The description is the title of the document. If you’re displaying list of documents then this would be a good property to use.
  • The Confidentiality property allows a privacy policy to control the access to a document. The policy can also use the generic tags functionality in FHIR.
  • The PrimaryLanguage element indicates exactly that – no surprises here. It is a code, and is bound to the IETF Language tag.
  • mimeType and format indicate how the document is represented – eg xml, pdf, msword etc.
  • Size allows a client to estimate download time of the document, and the hash can ensure integrity.
  • The Location is a URI that indicates from where the document can be downloaded. This does not need to be a FHIR server. The client will (generally) not know what this is when creating the resource as it will be related to the ID that the server assigns. However, either it or the service property is required, so it may be necessary to create a ‘dummy’ resource using the cid: prefix so the server knows it is not real – or define a service. You would define a local policy to describe this, which could be identified in the policyManager link above.
  • The service is used if the location is not known. You would use this if you weren’t using simple FHIR REST, so for the moment we’ll ignore it.
  • The context allows you to specify the clinical context of the document – at least the context that is useful in searching or displaying the document list. The period that the document refers to and the facility type are present, but you can add codes that make sense here as well.

For reference, the following fields need to have their options defined by the governing body using a ValueSet. These can either be defined directly in the ValueSet or be a sub-set of an external Terminology like LOINC or SNOMED.

  • type
  • subtype
  • docStatus
  • confidentiality
  • mimeType
  • format
  • context.code
  • context.facilityType

The recommended way to document this is to create a Profile resource that describes the implementation, and refers to the appropriate ValueSets – with the whole lot being saved in FHIR server/s so that they can be easily located. The option below shows a minimal profile that sets the ValueSet for the confidentiality property.

&lt;Profile xmlns=&quot;http://hl7.org/fhir&quot;&gt;
     &lt;text&gt;
         &lt;status value=&quot;additional&quot;/&gt;
         &lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;Minimal profile for confidentiality codes in DocumentReference&lt;/div&gt;
     &lt;/text&gt;
     &lt;name value=&quot;Elbonian XDS Profile&quot;/&gt;
     &lt;status value=&quot;draft&quot;/&gt;
     &lt;structure&gt;
         &lt;type value=&quot;DocumentReference&quot;/&gt;
         &lt;name value=&quot;XDSDocumentReference&quot;/&gt;
         &lt;element&gt;
             &lt;path value=&quot;DocumentReference.confidentiality&quot;/&gt;
             &lt;name value=&quot;ConfidentialityOptions&quot;/&gt;

             &lt;definition&gt;
                 &lt;short value=&quot;Confidentiality Code options&quot;/&gt;
                 &lt;formal value=&quot;Confidentiality Code options&quot;/&gt;
                 &lt;min value=&quot;1&quot;/&gt;
                 &lt;max value=&quot;1&quot;/&gt;
                 &lt;isModifier value=&quot;false&quot;/&gt;
                 &lt;binding&gt;
                     &lt;name value=&quot;List of confidentiality options&quot;/&gt;
                     &lt;isExtensible value=&quot;false&quot;/&gt;
                     &lt;referenceResource value=&quot;/ValueSet/ConfidentialityOptions&quot;/&gt;
                 &lt;/binding&gt;
             &lt;/definition&gt;
         &lt;/element&gt;
     &lt;/structure&gt;
 &lt;/Profile&gt;

and the ValueSet that it references could look like:

&lt;ValueSet xmlns=&quot;http://hl7.org/fhir&quot;&gt;
     &lt;text&gt;
         &lt;status value=&quot;additional&quot;/&gt;
         &lt;div xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;The value set for confidentiality codes in the elbonian document sharing
         project. The codes are defined directly by the valueset, rather than references to an external terminology&lt;/div&gt;
     &lt;/text&gt;
     &lt;name value=&quot;ConfidentialityOptions&quot;/&gt;
     &lt;description value=&quot;ConfidentialityOptions&quot;/&gt;
     &lt;status value=&quot;draft&quot;/&gt;
     &lt;!-- Define the  options in the resource rather than an external terminology--&gt;
     &lt;define&gt;
         &lt;system value=&quot;http://fhir.moh.elbonia.com/confidentiality&quot;/&gt;
         &lt;concept&gt;
             &lt;code value='N'/&gt;
             &lt;display value=&quot;Normal&quot;/&gt;
             &lt;definition value=&quot;That the document is of normal confidentiality - is able to be viewed for any authenticated user&quot;/&gt;
         &lt;/concept&gt;
         &lt;concept&gt;
             &lt;code value='H'/&gt;
             &lt;display value=&quot;High&quot;/&gt;
             &lt;definition value=&quot;Then the document is Highly confidential - eg Mental health - and can only be viewed by people authorized to access documents at that level&quot;/&gt;
         &lt;/concept&gt;
     &lt;/define&gt;
 &lt;/ValueSet&gt;

Finishing up…

In the previous post I promised that I would talk about the DocumentManifest resource. This is a new addition to the FHIR family, and has been introduced to support the ability for a document source to submit a collection of documents in a single batch as XDS does.

In truth, I’m not entirely clear how this resource should be used. It does have the recipient element, which provides the basis for a notification system, but beyond that the main value would seem to be that there can be more than a single document in a batch submission to the Repository server. I’ll update the post when I learn more.

So, we have saved a document in the repository and updated the registry. In the next post, we’ll switch our attention to the Document Consumer and discuss how to query the registry for documents, and to get the actual document itself.