Determining the #FHIR version

Jun 4, 2018

We’ve now published 3 FHIR milestone releases, and we’re working towards the 4th. We still haven’t clearly documented how you determine what version of FHIR is in use. There’s a reason for that: versioning is one of the most difficult issues to get right, and we wanted to get some real experience before we decided how to resolve this. Balloting the FHIR infrastructure as normative has forced us to finally come to resolution on this, after much long discussion. This post writes up what we decided in Cologne, which is what will be balloted in September.

There are 3 ways to determine the version of a resource:

  • The fhirVersion element in the Applicable CapabilityStatement
  • A parameter on the mime type that applies to the resource
  • Specifying a version specific profile on the resource itself

CapabilityStatement.fhirVersion

Whenever resources are exchanged, the applicable fhirVersion applies to the entire interaction, not just the resources. The semantics of the mime types, the RESTful URLs, the search parameters, and the overall interaction are bound to a particular FHIR version. The resource versions must be consistent with the overall interaction. It’s not possible for client/server (or, for messaging, sender/receiver) to have a coherent conversation without first agreeing on the version. The version of the interaction is specified in the CapabilityStatemet resource. The sequence works this way:

  • The server decides what version it is implementing, and states this in it’s CapabilityStatement
  • The client knows what FHIR version it uses
  • The first time the client connects to the server, it retrieves that CapabilityStatement and checks that the server version is the same
  • All interactions between the client and server use the same version

Clients should check the server’s capability statement before first using the server, but how often is at the discretion of the implementer, and this varies wildly. Some implementers only check the statement during the development cycle, while others check on the first connection for each process. Which is appropriate depends on a variety of circumstances, but implementers should note that the CapabilityStatement can change over time, even changing versions. Most servers won’t do that, but we don’t make a rule against it.

Mime Type Parameter

Many servers implement different end-points for different versions (e.g. test.fhir.org/r3 and test.fhir.org/r4, though unlike the test servers, most servers have the same logical content on the end-points). But this can be painful because it means that the same record has a different identity depending on the version of FHIR in use. (Actually, this can also be good as well - it depends on the context). A server can support multiple versions on the same end-point, if the client specifies which version to support using a mime type parameter:

GET [base]/metadata
Accept: application/fhir+json; fhirVersion=3.0

This is a request to return the CapabilityStatement for the server’s support of FHIR Release 3 (see below for the version table). The client will know that the server doesn’t support R3 if it gets an error in return, or if the capability statement that comes back has a different fhirVersion (which would mean that the server does not support the fhirVersion parameter).

The client must include the fhirVersion parameter on all following interactions.

The same parameter can be used anywhere Mime type is used to describe that a content contains a FHIR resource - such as in an Email attachment:

--MIME_boundary
Content-Type: application/fhir+xml; fhirVersion=1.0

the same technique can be used in a database, or any other kind of storage - just store the mime type (or the version) alongside the resource. This means that an application that is reading a resource knows what version the resource has, and therefore what parser to use, before reading the resource.

Version Specific Profile

There are some circumstances where applications handle ‘naked’ resources - that is, resources where there is no wrapping envelope to carry a mimetype version parameter (or any other indication of version). The most obvious is when resources are stored in files (although even then the version could be in the file e.g. [xxxxxxxxx].r2.json, but we couldn’t make any standard for this). When there’s no other alternative, the version has to be in the resources itself, and applications reading the resource have to scan the resource to determine the version and then read the resource as the correct version.

In these cases where the version must be placed in the resource itself, this is done by indicating that the resource conforms to a version specific profile:

{
  "resourceType" : "Patient",
  "meta" : {
    "profile" : ["http://hl7.org/fhir/3.0/StructureDefinition/Patient"]
  }
}

This method is actually applicable to all the previously published versions of FHIR, and already is valid (though we need to make sure that the end points described here resolve correctly).

Managing Versions

This means that there are 3 different methods for determining version, all of which are applicable all the time. In terms of use, we strongly recommend their use in the order documented:

  1. all exchange of FHIR resources will have a known version from the metadata - this always applies, and implementers should use this method whenever possible.
  2. When this is not enough, or when resources are not exchange, a version parameter should be stored alongside the resource, preferably using the mime type parameter documented above
  3. When there’s no other choice, use the meta.profile to indicate which version(s) a resource conforms to

There’s no order of preference between these methods - if the version of a resource or interaction is specified more than one way, the version statements must all agree with each other, or it is an error, and applications can proceed how they wish - usually, with some kind of error.

Version Table

FHIR R1 (DSTU 1) 0.0
FHIR R2 (DSTU 2) 1.0
FHIR R3 (STU3, or just R3) 3.0
FHIR R4 (yet to be published) 4.0

Intermediate balloted releases may be encountered occasionally. If so, the version string is the major/minor version from the publications directory. As of writing this, the current build release is 3.4, but this will change over time. There is no support for versions prior the publication of DSTU1.

Changes to the Specification

We will make 1 substantive change to the specification: documenting the use of the fhirVersion parameter. In addition, we’ll document the rest in the specification, but none of the rest is substantive change.

Footnote: Note that some implementers wished that we would introduce a specific element “fhir-version” : “3.0” in the Meta element, but we chose not do this because (a) this would create even more duplication, and also using the profile element is valid in all previously published versions of FHIR (in fact, some implementers are already using it).