FHIR extensions

Read and write the fields the base specification does not define, including complex extensions that nest further extensions inside.

You can read and write extensions - the fields the base specification does not define. Real-world data always carries some: a patient's birth place, their preferred pharmacy, attributes required by a national Implementation Guide. FHIR stores all of it in extension, a list that any resource or element can contain, where each entry is identified by a URL and holds one typed value.

What an extension looks like

An extension is plain data, e.g. a Patient with a birth place looks like this on the wire:

{
  "resourceType": "Patient",
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/patient-birthPlace",
      "valueAddress": {"city": "Amsterdam", "country": "NL"}
    }
  ]
}

Read extensions

Because the order of the extension list is never guaranteed, read extensions by their URL with a path matcher rather than by index:

# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

birth_place_url = 'http://hl7.org/fhir/StructureDefinition/patient-birthPlace'

class ReadBirthPlace(Service):
    name = 'demo.fhir.read-birth-place'

    def handle(self) -> 'None':

        client = self.fhir['FHIR.Sample']
        patient_id = '511a6231-361e-4b8e-8f9c-b183b7813f4d'
        patient = client.resources('Patient').search(_id=patient_id).get()

        # Select the extension by its URL and read the city from its value
        path = ['extension', {'url': birth_place_url}, 'valueAddress', 'city']
        city = patient.get_by_path(path)

        self.logger.info('Born in %s', city)

Nested extensions

Implementation Guides often define complex extensions whose value is a further list of sub-extensions. The standard patient-nationality extension is one - the outer extension has no value of its own, only inner ones:

{
  "url": "http://hl7.org/fhir/StructureDefinition/patient-nationality",
  "extension": [
    {"url": "code", "valueCodeableConcept": {"text": "Dutch"}},
    {"url": "period", "valuePeriod": {"start": "2004-05-01"}}
  ]
}

Matchers nest the same way the data does:

nationality_url = 'http://hl7.org/fhir/StructureDefinition/patient-nationality'

# From the outer extension by URL, into the inner one by URL, down to the value
path = [
    'extension', {'url': nationality_url},
    'extension', {'url': 'code'},
    'valueCodeableConcept', 'text',
]
nationality = patient.get_by_path(path)

Write extensions

To add an extension, append to the resource's extension list - creating the list first if the resource has none - and save:

# The resource may not have any extensions yet
if 'extension' not in patient:
    patient.extension = []

# Add the new one ..
patient.extension.append({
    'url': birth_place_url,
    'valueAddress': {'city': 'Amsterdam', 'country': 'NL'}
})

# .. and persist the change.
patient.save()

To replace an existing extension, filter it out by its URL first so the list never holds duplicates:

patient.extension = [item for item in patient.extension if item['url'] != birth_place_url]

patient.extension.append({
    'url': birth_place_url,
    'valueAddress': {'city': 'Rotterdam', 'country': 'NL'}
})

patient.save()

See also

PageWhat it covers
Path accessDotted paths, list indexes and the matchers used above
ResourcesCreate, read, update and delete any FHIR resource
FHIR in EuropeThe national programs whose guides define extensions

Learn more


Schedule a meaningful demo

Book a demo with an expert who will help you build meaningful systems that match your ambitions

"We evaluated 12 integration platforms and Zato was the only one to score 100%."

Philip Zuñiga, Assistant Professor, University of the Philippines