# 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 {#create-a-resource}

To build a new resource, call the `resource` method on a [connection](https://zato.io/docs/dev/healthcare/hl7/fhir/connections/index.html) 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`.

```python
# -*- 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 {#read-a-resource}

When you know a resource's ID, the `get` method reads it directly. To find resources by other criteria, use [searches](https://zato.io/docs/dev/healthcare/hl7/fhir/bundles/index.html).

```python
# 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](https://zato.io/docs/dev/healthcare/hl7/fhir/path-access/index.html) works too. To modify the resource and save it back, read it through a search instead, as shown below.

## Update a resource {#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.

```python
# 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:

```python
patient.refresh()
```

## Delete a resource {#delete-a-resource}

A call to `delete` removes the resource from the server:

```python
patient.delete()
```

## References between resources {#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:

```python
# 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 resolved to the full resource it points to:

```python
# 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 {#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:

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

## Learn the data model {#learn-the-data-model}

The FHIR specification lists every resource type with its attributes and their multiplicities - for example, the [Observation resource](https://hl7.org/fhir/observation.html) 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 {#see-also}

- [Searches and bundles](https://zato.io/docs/dev/healthcare/hl7/fhir/bundles/index.html) - Search parameters, result bundles and pagination
- [Path access](https://zato.io/docs/dev/healthcare/hl7/fhir/path-access/index.html) - Nested reads in single calls, with matchers for lists
- [Extensions](https://zato.io/docs/dev/healthcare/hl7/fhir/extensions/index.html) - Read and write the fields the base specification does not define
- [Connections](https://zato.io/docs/dev/healthcare/hl7/fhir/connections/index.html) - The Dashboard form and everything self.fhir accepts

## Learn more {#learn-more}

- [Healthcare interface engine](https://zato.io/docs/dev/healthcare/) - Clinical messages, FHIR, conversion and operations
- [HL7 v2 parsing](https://zato.io/docs/dev/healthcare/hl7/v2/parsing/) - Messages as typed objects, with field access and validation
- [MLLP channels](https://zato.io/docs/dev/healthcare/hl7v2/mllp/) - Receiving and sending HL7 v2 over MLLP sockets
- [FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/) - Read and write FHIR resources, with paths, bundles and extensions
- [HL7 v2 to FHIR](https://zato.io/docs/dev/healthcare/hl7/to-fhir/) - Converting v2 messages into FHIR bundles, codes and references included
- [EDIFACT](https://zato.io/docs/dev/healthcare/edifact/) - Parsing interchanges, dialects and the transports they arrive on
- [Transformation](https://zato.io/docs/dev/healthcare/transformation/) - One message in, another standard out, in ordinary Python
- [Audit log](https://zato.io/docs/dev/healthcare/audit-log.html) - Every message with its acknowledgment, searchable by patient identifier
- [AI in clinical interfaces](https://zato.io/docs/dev/healthcare/ai/) - Services calling LLMs and AI agents calling clinical services as tools
