FHIR API Basics

The Oystehr 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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const createdResource/*: Patient*/ = await oystehr.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, Oystehr 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 Oystehr 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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const readResult/*: Patient*/ = await oystehr.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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const updateResult/*: Patient*/ = await oystehr.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

JSON Patch

The FHIR specification requires one of a few implementations for PATCH behavior (opens in a new tab). The Oystehr 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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const patchResult/*: Patient*/ = oystehr.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.

ℹ️
Note that the semantics for using JSON Patch with Batch or Transaction requests is different than with normal PATCH requests. Please see here for more information.

XML Patch

XML Patch is not supported by the Oystehr FHIR service. Please use JSON Patch instead.

FHIRPath Patch

FHIRPath Patch is not supported by the Oystehr FHIR service. Please use JSON Patch instead.

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 Oystehr 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 (opens in a new tab) 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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const createdPatient = await oystehr.fhir.create<Patient>({
  resourceType: 'Patient',
});
 
// a later update to the patient record
const updateResult/*: Patient*/ = await oystehr.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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
const createdPatient = await oystehr.fhir.create<Patient>({
  resourceType: 'Patient',
});
 
// a later patch to the patient record
const patchResult/*: Patient*/ = oystehr.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 v3 SDK:

import { Patient } from 'fhir/r4b'; // npm install @types/fhir
import Oystehr from '@oystehr/sdk'
 
const oystehr = new Oystehr({
  accessToken: "<your_access_token>",
});
 
await oystehr.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