FHIR API Basics

The ZapEHR FHIR API is a RESTful API conforming to the FHIR specification (opens in a new tab). It uses the JSON format (opens in a new tab) for resource representation.

Anatomy of a FHIR Resource

A FHIR resource is a JSON object with a resourceType property and a set of additional properties that vary depending on the resource type. The Patient resource is at the heart of the FHIR universe, and many other FHIR resources reference Patient resources. Let's take a look at an example Patient resource:

{
  "resourceType": "Patient",
  "active": true,
  "name": [
    {
      "given": ["Jon"],
      "family": "Snow"
    }
  ],
  "address": [
    {
      "use": "home",
      "type": "physical",
      "text": "Winterfell"
    }
  ]
}
  • The resourceType of Patient is what makes this a Patient FHIR resource.
  • The active property is a boolean indicating whether this Patient record is in active use.
  • You can see from the name property that the patient the FHIR resource represents is named Jon Snow. The name property is an array of type HumanName (opens in a new tab), which allows for the possibility of recording a patient's official name, maiden name, nickname, etc.
  • The address property is also an array so you can document a number of addresses for a patient. This can be useful when a patient's address changes and you want to keep a record of their previous address.

Compare our Jon Snow Patient resource to the Patient resource definition (opens in a new tab) in the FHIR specification, and you'll see we are just scratching the surface of the information you can record in a Patient resource.

All of the properties are optional, so you can record as much or as little information as you need for your use case. It's common for a Patient resource to be created with limited information when a patient is first registered, and for that resource to grow over time as more information becomes available.

Create

Request

You can create a Patient resource by making a POST request to the Patient endpoint. The body of the request should be a JSON representation of the Patient resource. Patients can also be created using the SDK and the Developer Console.

Create a FHIR Patient with the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const createdResource: Patient = await zapehr.fhir.create<Patient>({
  resourceType: 'Patient',
  active: true,
  name: [
    {
      given: ['Jon'],
      family: 'Snow',
    },
  ],
  address: [
    {
      use: 'home',
      type: 'physical',
      text: 'Winterfell',
    },
  ],
});

Any time a FHIR Resource is created, updated, or deleted, ZapEHR automatically creates a FHIR Provenance resource to track the change.

Response

The API responds with status code 201 Created and a response body in JSON format containing the created Patient resource:

{
  "resourceType": "Patient",
  "active": true,
  "name": [
    {
      "given": ["Jon"],
      "family": "Snow"
    }
  ],
  "address": [
    {
      "use": "home",
      "type": "physical",
      "text": "Winterfell"
    }
  ],
  "id": "2419a78e-4c0a-411d-b9e2-90dc081f5efa",
  "meta": {
    "versionId": "6b43753b-08f1-4c71-afa8-c83704e42aab",
    "lastUpdated": "2023-11-15T17:48:11.240Z"
  }
}

There are a few new properties added to the FHIR Patient resource now that it has been created:

  • The id property is a unique identifier for the Patient resource. This identifier is generated by the ZapEHR FHIR API and is guaranteed to be unique across all Patient resources.
  • The meta property contains metadata about the Patient resource. The lastUpdated property is a timestamp indicating when the Patient resource was last updated. The versionId property is a unique identifier for the current version of the Patient resource. See Resource History for more information about FHIR resource versioning.

Read

Request

You can read a Patient resource by making a GET request to the Patient endpoint with the Patient resource's id as a path parameter. Patients can also be read using the SDK and the Developer Console.

Read a FHIR Patient with the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const readResult: Patient = await zapehr.fhir.get<Patient>({
  resourceType: 'Patient',
  resourceId: '2419a78e-4c0a-411d-b9e2-90dc081f5efa',
});

Response

The API responds with status code 200 OK and a response body in JSON format containing the Patient resource.

{
  "resourceType": "Patient",
  "active": true,
  "name": [
    {
      "given": ["Jon"],
      "family": "Snow"
    }
  ],
  "address": [
    {
      "use": "home",
      "type": "physical",
      "text": "Winterfell"
    }
  ],
  "id": "2419a78e-4c0a-411d-b9e2-90dc081f5efa",
  "meta": {
    "versionId": "6b43753b-08f1-4c71-afa8-c83704e42aab",
    "lastUpdated": "2023-11-15T17:48:11.240Z"
  }
}

Update

You can update a FHIR resource with either PUT or PATCH requests. PUT requests replace the entire resource, while PATCH requests only update the properties you specify.

PUT

Update a Patient with PUT using the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const updateResult: Patient = await zapehr.fhir.update<Patient>({
  resourceType: 'Patient',
  id: '2419a78e-4c0a-411d-b9e2-90dc081f5efa',
  name: [{
    given: [
      'Aegon'
    ],
    family: 'Targaryen'
  }],
});

The meta property is system-generated and read-only, so if you include it in your request, the API will just ignore it. The id property is required in the resource content, and it must match the id value passed in the URL path.

The API responds with status code 200 OK and a response body containing the Patient resource, just like the Create and Read responses.

PATCH

The FHIR specification requires one of a few implementations for PATCH behavior (opens in a new tab). The ZapEHR FHIR API implements JSON Patch (opens in a new tab). The JSON Patch implementation requires a Content-Type header of application/json-patch+json and a request body containing an array of operations to perform on the resource.

Update a Patient with PATCH using the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const patchResult: Patient = zapehr.fhir.patch<Patient>({
  resourceType: 'Patient',
  resourceId: '2419a78e-4c0a-411d-b9e2-90dc081f5efa',
  operations: [
    {
      op: 'replace',
      path: '/name',
      value: [
        {
          given: [
            "Aegon"
          ],
          family: "Targaryen"
        }
      ],
    },
  ],
});

The API responds with status code 200 OK and a response body containing the Patient resource, just like the Create and Read responses.

Handling Resource Contention with Optimistic Locking

To better handle concurrent write operations performed on resources, FHIR supports "weak" optimistic locking (opens in a new tab). When this behavior is enabled, the ZapEHR FHIR service will not allow a resource to be updated if the client's version of the resource is out of date. To enable optimistic locking, the client must include the If-Match header with the version ID of the resource it read before attempting to update the resource.

Optimistic locking is supported for both PUT and PATCH requests. The SDK makes it easier to use this feature by only requiring the resource version ID, instead of the whole If-Match header.

Update a Patient with optimistic locking using the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const createdPatient = await zapehr.fhir.create<Patient>({
  resourceType: 'Patient',
});
 
// a later update to the patient record
const updateResult: Patient = await zapehr.fhir.update<Patient>({
  resourceType: 'Patient',
  id: createdPatient.id,
  name: [{
    given: [
      'Aegon'
    ],
    family: 'Targaryen'
  }],
}, { optimisticLockingVersionId: createdPatient.meta?.versionId });

Patch a Patient with optimistic locking using the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
const createdPatient = await zapehr.fhir.create<Patient>({
  resourceType: 'Patient',
});
 
// a later patch to the patient record
const patchResult: Patient = zapehr.fhir.patch<Patient>({
  resourceType: 'Patient',
  resourceId: createdPatient.id,
  operations: [
    {
      op: 'replace',
      path: '/name',
      value: [
        {
          given: [
            "Aegon"
          ],
          family: "Targaryen"
        }
      ],
    },
  ],
}, { optimisticLockingVersionId: createdPatient.meta?.versionId });

Delete

Delete a resource by making a DELETE request to the Patient endpoint with the resource's id as a path parameter.

Delete a Patient using the SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import zapehr from '@zapehr/sdk'
 
zapehr.init({
  ZAPEHR_ACCESS_TOKEN: "<your_access_token>",
});
 
await zapehr.fhir.delete<Patient>({
  resourceType: 'Patient',
  resourceId: '2419a78e-4c0a-411d-b9e2-90dc081f5efa',
});

The API responds with status code 204 No Content and an empty response body.

Reference Properties

Most FHIR resources have references which relate them to other resources.

FHIR resources can reference other FHIR resources. For example, a Patient resource can reference a Practitioner resource through the generalPractitioner (opens in a new tab) property to indicate the patient's primary care provider.

The Reference data type (opens in a new tab) is used to relate resources to each other in a number of ways.

Relative references

One of the most common ways is to set only the reference property with what the FHIR spec calls a relative URL:

{
  "resourceType": "Patient",
  "generalPractitioner": [
    {
      "reference": "Practitioner/2419a78e-4c0a-411d-b9e2-90dc081f5efa"
    }
  ]
}

The relative URL tells us that the referenced resource is located in the same FHIR server as the referencing resource. You could fetch the Practitioner by using the Read endpoint like this:

GET https://fhir-api.zapehr.com/r4/Practitioner/2419a78e-4c0a-411d-b9e2-90dc081f5efa