Working with FHIR resources

Manage Patient, Observation and every other clinical resource in a few lines of Python - create, read, update and delete without hand-built REST calls.

You can create, read, update and delete any FHIR resource from Python services - Patient, Observation, Appointment and the rest of the R4 model.

Create a resource

To build a new resource, call the resource method on a connection client with the resource type. Fields can be passed as keyword arguments or assigned afterwards, using either attribute or dictionary syntax - a resource behaves like both an object and a dict. The server receives nothing until you call save.

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

# Zato
from zato.server.service import Service

class CreatePatient(Service):
    name = 'demo.fhir.create-patient'

    def handle(self) -> 'None':

        client = self.fhir['FHIR.Sample']

        # Build a new Patient with initial data ..
        name = [{'family': 'Chalmers', 'given': ['Peter']}]
        patient = client.resource('Patient', name=name)

        # .. both syntaxes below are equivalent ..
        patient.birthDate = '1974-12-25'
        patient['gender'] = 'male'

        # .. and this is what stores the patient in the server.
        patient.save()

        # The server assigned an ID during the save
        self.logger.info('Created %s', patient.id)

Read a resource

When you know a resource's ID, the get method reads it directly. To find resources by other criteria, use searches.

# Read one resource by its type and ID
patient = client.get('Patient', '511a6231-361e-4b8e-8f9c-b183b7813f4d')

self.logger.info('Family name is %s', patient['name'][0]['family'])

A direct read returns the resource's data - fields respond to both attribute and dictionary access, and path access works too. To modify the resource and save it back, read it through a search instead, as shown below.

Update a resource

A resource fetched through a search supports save, which sends the full resource back to the server. To send only selected fields, call patch with those fields alone.

# Fetch the resource by its ID ..
patient_id = '511a6231-361e-4b8e-8f9c-b183b7813f4d'
patient = client.resources('Patient').search(_id=patient_id).get()

# .. change a field and store the whole resource ..
patient.birthDate = '1974-12-26'
patient.save()

# .. or send only one field, leaving the rest untouched.
patient.patch(birthDate='1974-12-27')

If another system may have modified the resource in the meantime, the refresh method re-reads it from the server:

patient.refresh()

Delete a resource

A call to delete removes the resource from the server:

patient.delete()

References between resources

FHIR resources point at each other through references, e.g. an Appointment refers to the Patient who will attend it. Pass one resource inside another and the client builds the reference for you:

# Create a new appointment for an already saved patient
appointment = client.resource('Appointment')

appointment.status = 'booked'
appointment.participant = [{'actor': patient, 'status': 'accepted'}]
appointment.start = '2027-01-11T11:11:11.111+00:00'
appointment.end   = '2027-01-11T12:11:11.111+00:00'

appointment.save()

Going the other way, a reference found in one resource can be turned into the full resource it points to:

# This is a reference, e.g. Patient/511a6231-361e-4b8e-8f9c-b183b7813f4d ..
actor = appointment['participant'][0]['actor']

# .. and this fetches the actual Patient from the server.
patient = actor.to_resource()

Resources as plain dicts

The serialize method returns a plain Python dict of a resource, e.g. to log it, store it elsewhere or return it from a service:

data = patient.serialize()
self.response.payload = data

Learn the data model

The FHIR specification lists every resource type with its attributes and their multiplicities - for example, the Observation resource page shows all the fields an Observation is composed of. To learn a resource, create a sample of it on a test server with the code above, read it back and compare the result with what the specification says.

See also

PageWhat it covers
Searches and bundlesSearch parameters, result bundles and pagination
Path accessNested reads in single calls, with matchers for lists
ExtensionsRead and write the fields the base specification does not define
ConnectionsThe Dashboard form and everything self.fhir accepts

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