FHIR Nuts & Bolts: Versioning

By Analysts
EIM Practice Director Chris Grenz

During the Madrid HL7 WGM last week there was a lively discussion on inclusion of FHIR versions in resource instance data to allow systems to cope with the changing schemas/profiles during the STU process and the following normative period.

 

The discussion also touched on versioning APIs. In the ReST space there seems to be relative consensus that endpoints should be versioned due to breaking changes in the API during the STU period. Messaging interfaces are less clear cut but focus more on the content side as I will here.

The goals of content versioning as I understand them center on:

  • Systems use the version to select the correct profile and/or parser/validator when receiving FHIR data.
  • Mapping content version to version and to other models requires selecting the correct maps.

 

FHIR Things to Consider

  • (Near) future versions of FHIR will include both normative and STU content.
  • Normative resources will be cross-version compatible, and servers and clients must handle all normative content for interoperability to be achieved.

I expect this to mean that optional, non-modifier elements may be added to normative resources. It follows that systems should ignore non-modifier content it doesn't understand and assume this is an element added in a later version. This makes things pretty "loose" in a conformance sense since invalid elements can't be rejected. This is a separate issue.

 

Systems Things to Consider

  • Double parsing is bad. Having to read the instance to determine how to read the instance is brittle at best. That said, FHIR already includes resourceType as a JSON element and as the root element in XML instances. The shark is jumped.
  • Persistence models will need to accommodate a mix of versions or mappings between a canonical version and others. These concerns are "behind" the API and explicitly not part of the standard.

 

Solution Options
Based on the live discussions, there are a few options out there:

 

Context Based
Communication of version outside the content payload:

 

API Endpoint – version context consistent by base URL. Breaks content URIs and can't deal with mixed version content. This is the common model today, but the STU/normative mix isn't yet in play.

 

MIME Type – add the FHIR version to the MIME type: application/fhir+xml?version=3.0.1. Specifics ("depth" of version number) TBD.

 

Embedded
Communication within the instance data. Suffers from the double parsing problem, but resourceType may have already made that inevitable. These solutions fit into two buckets – adding the FHIR version string somewhere and using the type system (profiles).
 

FHIR Version Somewhere – (+) easy to understand, direct. (-) Hinders interoperability when parsers start to check instance versions. (-) Adds version comparison logic alongside URL based profile keys.

New meta element
<Patient>
<meta>
<fhirVersion value="3.0.1" />
</meta>
</Patient>

 

By extension for better backwards compatibility, although backwards compatibility is explicitly the issue here!
<Patient>
<meta>
<extension url="http://hl7.org/.../meta-version">
<valueString value="3.0.1" />
</extension>
</meta>
</Patient>

 

With a tag which fits nicely in the existing model:
<Patient>
<meta>
<tag>
<system value="http://hl7.org/.../meta-version" />
<code value="3.0.1" />
</tag>
</meta>
</Patient>

 

In Bundle. FHIR messages are wrapped with Bundle (start with a MessageHeader) so adding version to the Bundle would cover use cases not covered by a versioned ReST endpoint.
<Bundle>
    ...

<fhirVersion value="3.0.1" />
    ...
</Bundle>

 

Profile-based metadata – point to version specific resource profiles during the STU period and then use the canonical version once normative.

<Patient>
<meta>
<profile value="http://hl7.org/fhir/STU3/StructureDefinition/Patient" />
</meta>
</Patient>

 

Instances without a meta.profile entry will be interpreted using system specific assumptions. In a system supporting normative content, I'd assume undeclared content to be normative content. In Grahame's DSTU2 endpoint, I'd assume DSTU2 (as will he!).

 

Guidance on inclusion of meta.profile would be a SHOULD for normative content and a SHALL for STU content.

 

A Case for Profile-Based Versioning
Having been an implementer since pre-DSTU1, versioning of FHIR content has been a persistent issue for us. I admit to having a bit of the "version fatigue" I've heard a few discuss at FHIR get-togethers. What I can't accept though is a solution that creates artificial version tiers that will inevitably lead to hard lines segmenting FHIR support.

 

Here's why the profile-based system is the most capable and elegant option here:

 

Mixed Content– The mix of STU and normative content we'll be living in for decades means that a single version number doesn't well describe the content of a system. On a resource by resource basis, comparing versions will yield resources that are:

  • Structurally Identical
  • Compatible (always for normatives, incidentally for STUs)
  • Incompatible (between STUs)

 

The profile-based method allows resources to individually indicate their conformance. For example, a STU5 bundle might include a normative Patient and an STU5 CarePlan wrapped in a normative Bundle.

 

We'd keep the requirement that a single instance (here Bundle) can't mix versions – no STU4 mixed with STU5. This means any normative mixes with any other normative and a single STU level.

 

Normative Handling – This method explicitly avoids differentiating between post-normative versions of resources in line with the intent of HL7 to ensure compatibility of all normative content. ALL normative content is described (and parsable) using a normative StructureDefinition identified by the canonical URL. Effectively, all normative content is a single version in the resource instance context, critical to long term interoperability.

 

Implementation Purity – Parsers and validators use StructureDefinitions directly. They are inherent to their operation, and their identifying URLs are the keys. FHIR version numbers are not. Mixing version logic with URL logic will add complexity and arbitrary rules without adding value.

 

Double Parsing in Practice – In the vast majority of implementations, documents are first parsed into an XML DOM or into a JSON object. Validation occurs next on that data structure based on a selected profile.

 

The only true double parsing would occur in the case of "stream" validation of resources, e.g. using a SAX event-based XML parser. Since the meta element is at the top of the XML resource, determining the relevant profile can happen very early before much parsing cost has been incurred.

 

The ONLY case where true double parsing would occur would be in a JSON stream parser with an instance placing the meta tag late in the document. A unicorn of a use case, (I think?). And, this situation already suffers from a late positioned resourceType element.

 

Conclusion
The elegance of the FHIR conformance system gives implementers a powerful mechanism for describing and validating FHIR content. Working within this system allows for systems from low to high complexity to support the level appropriate for the job at hand.

 

Adding version numbers to the mix allows the most naive systems a quick path to content handling. But it comes at the cost of interoperability, of additional complexity in the median use case, and of unneeded optionality for specifiers.