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!

 

 

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.

Fixed code sets in FHIR

One of the common use cases for FHIR is going to be to create a ‘proxy’ or ‘façade’ FHIR server that provides a FHIR interface against an existing data source – and this is what we are doing at Orion Health in front of our Patient Administration System. (We’re actually building a rather cool mobile medication administration app – hope I’m allowed to say that!).

One of the issues we’ve come across is where there is a property with datatype of code and a fixed set of code values (a codeset) – such as  MedicationPrescription.status.

The problem we are facing is that in the ‘back end’ system, this field is a configurable set of values – and it often won’t match the values defined in FHIR. This is bad enough for optional properties, but even worse when the property is a required one – such as MedicationAdministration.status.

Now there are very good reasons why the workgroup that designed these resources have made the codes a fixed set – they are important properties that a recipient must understand to safely use the resource – and we are about interoperability after all. But it’s still a problem we need to solve.

I can think of a few possibilities for us.

 Option 1 is to change the codeset in the backend system to that defined in the FHIR resource – perhaps a bit unlikely…

 Option 2. Ideally, every value in the back end system can be mapped to one of the values from the fixed code set – with an acceptable loss of fidelity. Then, you can create an extension to hold the original value. In this way a recipient who doesn’t understand your custom codeset can still safely process the resource (using the defined property) but internal clients can apply whatever extra logic is supported by the enhanced set in the extension.

For example, the MedicationPrescription resource has a status property of which one of the values is ‘on-hold’. If the backend system has a number of values that could mean this (on-hold due to an operation, on-hold due to other therapy, on-hold because the pharmacy has run out) then you can set the status value to on-hold, and the extension can contain the more precise value. Incidentally, this might be one of the few places where a Coding datatype is appropriate.

 Option 3. If you have values that simply cannot be mapped in this way then you can use a modifierExtension on the property itself to carry the extra value. This severely reduces the interoperability of your resource of course, as a recipient must be able to understand and process your custom value – and should reject the resource if it cannot.

(It may not have been obvious that resource properties can have extensions as well as the resource themselves – check out the spec for more details. In fact, it’s possible to extend a datatype if you need to!)

If you do find yourself in this position, it would pay to ask a question through one of the various FHIR support channels – you might get advice about a value you can use, or if your use case is compelling enough the codeset can be extended in FHIR itself.

 So there you go. A price of being interoperable is that you have to conform to a set of agreed behavior and content – and sometimes that means compromise. Hopefully there will always be some way to achieve the business requirements, and especially in this DSTU phase of FHIR changes to the spec are quite possible – if there is a good enough reason.

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.