FHIR Chat · Handling complex types in inter-version extensions · implementers

Stream: implementers

Topic: Handling complex types in inter-version extensions


view this post on Zulip Lloyd McKenzie (Aug 16 2021 at 22:16):

In R4 of the core spec here, we say
Where complex data types have no equivalent in an earlier version, use a complex extension, containing extensions also following this pattern. Follow the same pattern for any elements not found in data types in earlier versions
However, we don't explain how that works in practice in a few ways:

  • how does the data type being represented get exposed?
  • what are the URLs for the complex extension?
  • what happens if the element in question is a choice - between types that are part of the version the extension is referencing and types that aren't? E.g. what is the name of the value[x] when the type isn't a supported type?

These questions come from FHIR#31721 from @Chris Moesel. We don't (yet) have good answers and are seeking ideas.

view this post on Zulip Josh Mandel (Aug 16 2021 at 23:21):

EXAMPLE: NEW-DATATYPE-IN-CHOICE.

Let me kick things off with one example from FHIR R7, where (let's imagine) Observation.value[x] supports a new complex type called SensorData that for the sake of argument looks like

{
  "point": [{
      "offset": "int64 count of microseconds from the measurement start",
      "data": "int64 value measured by sensor"
  }]
}

(is this even a legal for Observation to do in FHIR R7? I'm not 100% sure. Technically "Additional data types may be added to elements which are already expressed as a choice of data types only if those elements are optional", and Observation.value is ... min cardinality zero... but I'm not sure what that implies with respect to "optional".)

So in R7, we'd have:

{
  "resourceType": "Observation",
  "valueSensorData": {
    "points": [
      {"offset": "0", data: "800"},
      {"offset": "100", data: "900"},
    ]
  }
}

And back-porting to R4 (assuming we map R5's int64 primitive to "string" in R4, which seems reasonable and, incidentally, like something we should not forget to write down!)...

{
  "resource": "Observation",
  "_valueSensorData": {  // (A) this seems wrong-- I'm not sure what element to attach these too
    "extension": [{
      "url": "http://hl7.org/fhir/7.0/StructureDefinition/extension-SensorData",
       "extension": [{
        "url": "point",  // (B) can we use "short" names for complex extension innards?
        "extension": [{
          "url": "offset", // (C) and if so, do we worry about ambiguity at different levels fo depth?
          "valueString": "0"
        }, {
          "url": "data",
          "valueString": "800"
        }]
      }]
    }, {
        "url": "point",
        "extension": [{
          "url": "offset",
          "valueString": "100"
        }, {
          "url": "data",
          "valueString": "900"
        }]
      }]
    }]
  }
}

view this post on Zulip Lloyd McKenzie (Aug 17 2021 at 01:23):

The element name must be one that's valid in the R4 schema. _valueSensorData wouldn't be.
Perhaps what we should have is an extension on Observation with a URL of "http://hl7.org/fhir/4.0/StructureDefinition/Observation.value"?

view this post on Zulip Lloyd McKenzie (Aug 23 2021 at 21:27):

Poking on this - please share your thoughts

view this post on Zulip Chris Moesel (Aug 23 2021 at 21:50):

Thanks for the poke. I've already implemented support for inter-version extensions in SUSHI and had to make some assumptions/guesses regarding some of this behavior. I'll look at my code tomorrow and let you know where I landed on some of these. Not saying we need to go the way I did -- but will just add that info as a data point (and I of course will update SUSHI to reflect whatever we ultimately decide).

view this post on Zulip nicola (RIO/SS) (Aug 24 2021 at 05:19):

First-class extensions would allow us forward compatibility, but "it's too late ;("

view this post on Zulip Chris Moesel (Aug 24 2021 at 13:39):

  • how does the data type being represented get exposed?
  • what are the URLs for the complex extension?

We had to implement some of this in SUSHI. At the time, our approach was to glean what we could from docs, Zulip, and IG Publisher behavior. Here is an example of the result when creating an instance of R4 MedicationRequest w/ an extension to use R5 MedicationRequest.medication (which is a CodeableReference):

{
  "resourceType": "MedicationRequest",
  "id": "MyMedRequestInstanceWithCodeableReferenceExtension",
  "extension": [
    {
      "url": "http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.medication",
      "extension": [
        {
          "url": "concept",
          "valueCodeableConcept": {
            "coding": [{ "code": "76388-713-25", "system": "http://hl7.org/fhir/sid/ndc" }]
          }
        },
        {
          "url": "reference",
          "valueReference": {
            "reference": "Medication/MyMedication"
          }
        }
      ]
    }
  ],
  "status": "completed",
  "intent": "order",
  "medicationReference": {
    "reference": "Medication/MyMedication"
  },
  "subject": {
    "reference": "Patient/Bob"
  }
}

First, note that we still had to put in medicationReference too, since medication[x] is 1..1. Kind of a bummer.

As you can see, we used the element names (concept, reference) as relative URLs in the complex extension. At one point we had tried using absolute extension URLs for the sub-extensions (e.g., http://hl7.org/fhir/5.0/StructureDefinition/extension-CodeableReference.concept instead of concept).
We thought this might be nice since you re-use other inter-version extensions rather than redundantly defining them inline in the complex extension. But... the IG Publisher was having none of that, so we reverted and stuck to inline relative URLs for complex extensions.

That said, the IG Publisher actually chokes on the example above too. We could only get it working with the IG Publisher for complex extensions representing a BackboneElement. When we tried to represent a truly new datatype (as in above), IG Publisher complains:

java.lang.Exception: Error generating snapshot for MyMedRequestProfileWithCodeableReferenceExtension(MyMedRequestProfileWithCodeableReferenceExtension): Unable to generate snapshot for http://example.org/StructureDefinition/MyMedRequestProfileWithCodeableReferenceExtension in /Users/cmoesel/dev/fsh/ImpliedExtensionsProject/fsh-generated/resources/structuredefinition-MyMedRequestProfileWithCodeableReferenceExtension
...
Caused by: org.hl7.fhir.exceptions.DefinitionException: StructureDefinition http://hl7.org/fhir/5.0/StructureDefinition/extension-MedicationRequest.medication at Extension.value[x]: illegal constrained type CodeableReference from base64Binary, boolean, canonical, code, date, dateTime, decimal, id, instant, integer, markdown, oid, positiveInt, string, time, unsignedInt, uri, url, uuid, Address, Age, Annotation, Attachment, CodeableConcept, Coding, ContactPoint, Count, Distance, Duration, HumanName, Identifier, Money, Period, Quantity, Range, Ratio, Reference, SampledData, Signature, Timing, ContactDetail, Contributor, DataRequirement, Expression, ParameterDefinition, RelatedArtifact, TriggerDefinition, UsageContext, Dosage, Meta in http://hl7.org/fhir/StructureDefinition/Extension

The message seems a little odd since we're actually not trying to constrain anything to CodeableReference directly (in fact, that's the point).

view this post on Zulip Chris Moesel (Aug 24 2021 at 14:39):

what happens if the element in question is a choice - between types that are part of the version the extension is referencing and types that aren't? E.g. what is the name of the value[x] when the type isn't a supported type?

We punted on this one because there was no clear answer. As you noted, there is no way to legally introduce a new type to a choice (including Extension.value[x]). So if someone had an extension that pointed to a choice type, and that choice type contained new data elements, we just filtered those new types out as unrepresentable. Not ideal, but the best we can do sans any actual specification of approach.

It's difficult to determine the right approach here. I think the best thing might be Lloyd's suggestion. @Lloyd McKenzie - you suggested a top-level extension w/ URL: http://hl7.org/fhir/4.0/StructureDefinition/Observation.value

  • We were talking about representing a choice from hypothetical FHIR 7.0, so did you mean 7.0 (not 4.0)?
  • Is there a reason the extension ends w/ .value rather than .value[x]? According to 2.7.0.7, "The [Path] is actually the ElementDefinition.id from the relevant StructureDefinition for the element" - so I think it should be value[x]?

This still does not answer what should be done if the original value[x] is 1..1. It would be hard to come up w/ a generic approach because there is no guarantee that a given choice type exists in the choice (e.g., we can't say "always use valueString" because not all choices have a string choice).

The other question is that if this represents something like the value of an Observation, and we're putting that value in an extension, then is that technically a modifierExtension? It does change the meaning of the Observation -- and if someone were to process the Observation without knowledge of the extension, then they'd be processing the wrong value element.


Last updated: Apr 12 2022 at 19:14 UTC