Skip to main content

FHIR Basics

Why FHIR?

Medplum stores healthcare data using the FHIR standard. Storing data according to this standard provides developers with the following benefits:

  • Interoperability: Increasingly, healthcare partners are exposing their data via FHIR APIs. Storing your data according to FHIR spec smooths the path to interoperating with multiple partners
  • Future Proofing: The healthcare ecosystem is complex and fragmented. As they encounter these complexities, many digital health companies end up performing costly data migrations. The FHIR spec anticipates many of the complexities that arise in the healthcare domain, helping teams avoid these backend rewrites.

While FHIR is quite powerful, it can have a bit of a learning curve. The page will go over the basic concepts for understanding FHIR data in Medplum. For more information, you can check out the official FHIR documentation.

Storing Data: Resources

A core data object in FHIR is called a Resource. You can think of Resources as objects in object oriented languages.

The FHIR standard defines over 150 Resource Types that model broad range of healthcare-specific concepts. These include concrete entities (Patient, Medication, Device) as well as abstract concepts (Procedure, CarePlan, Encounter).

Each field in a resource is called an Element, each of which can be a primitive type (e.g. string, number, date) or a complex type (e.g. HumanName).

Lastly, all resources have an id element, which is a server-assigned identifier that serves as their primary key.

Example Patient

The example below shows an example Patient resource. Here we can see that the Patient contains multiple elements, including name, telecom, and address.

{
// Resource Type (i.e. "class name")
"resourceType": "Patient",
// Unique id for this resource
"id": "j_chalmers",
// Patient Name (could have multiple)
"name": [
{
"use": "official",
"family": "Chalmers",
"given": ["Peter", "James"]
},
{
"use": "usual",
"family": "Chalmers",
"given": ["Jim"]
}
],
// Phone + email info
"telecom": [
{
"system": "phone",
"value": "(03) 3410 5613",
"use": "mobile"
}
],
// Address (could have multiple)
"address": [
{
"use": "home", // 'home', 'office', etc.
"line": ["534 Erewhon St"],
"city": "PleasantVille",
"district": "Rainbow",
"state": "Vic",
"postalCode": "3999",
// Single string version of address, used for display
"text": "534 Erewhon St PeasantVille, Rainbow, Vic 3999"
}
]
}

Linking Data: References

When working with FHIR, clinical data is often split across multiple resources. For example a prescription is related to the receiving patient, and a diagnostic report may consist of multiple observations.

To create a link between objects, we use Reference elements. A FHIR Reference is an element that functions like a foreign key in traditional relational databases to create 1-to-1 or many-to-many relationships between resources.

Reference elements have the following structure:

{
"reference" : ":resourceType/:id", // Resource type + unique id of the referenced Resource
"display" : string, // Display string for the reference
"type" : uri, // Resource type (if using a "logical reference")
"identifier" : Identifier
}

In Medplum, we will typically only use the reference and display elements.

Example: Linking a MedicationRequest to a Patient and Practitioner

The example below shows a resource modeling a prescription (i.e. MedicationRequest) with two references: subject (i.e. the patient) and requester (i.e. the requesting physician).

{
"resourceType": "MedicationRequest",
"id": "medrx002",
// Reference to the patient for whom medication is being ordered
"subject": {
"reference": "Patient/pat1",
"display": "Donald Duck"
},
"dosageInstruction": [
{
"text": "Take one tablet daily as directed"
}
],
// Reference to the requesting physician
"requester": {
"reference": "Practitioner/f007",
"display": "Patrick Pump"
}
}

FHIR offers both a REST API and GraphQL API to query, search, sort, and filter resources by specific criteria (see this blog post for tradeoffs between REST and GraphQL).

FHIR resources cannot be searched by arbitrary fields. Instead, the specification defines specific search parameters for each resource that can be used for queries.

Refer to the Medplum search documentation for a more in-depth tutorial on FHIR search.

Standardizing Data: Codeable Concepts

The healthcare system commonly uses standardized coding systems to describe healthcare share information between organizations about diagnoses, procedures, clinical outcomes, billing.

Some of the most commonly used code systems in the U.S. are:

Because there are multiple code systems for many domains, the same concept can be defined in multiple code systems. To handle this mapping from concept to system, the FHIR defines the CodeableConcept element type.

A CodeableConcept consists of two parts:

  • A text element - describes the concept in plain language
  • A coding element - an array of (system, code) pairs that provide the standard code for the concept within each code system.

FHIR CodeableConcepts use the system element to identify each code system within the coding array. By convention, FHIR uses absolute URLs to enforce that these systems are a globally unique namespace. However, these URLs do not always point to hosted web sites.

Refer to this blog post for a longer discussion of system strings.

Refer to the FHIR official documentation for a list of systems for common healthcare code systems.

Below is an example CodeableConcept, that defines the medication Tylenol, in both the RXNorm or NDC systems.

  {
text: 'Tylenol 325 MG Oral Tablet',
coding: [
{
system: 'http://hl7.org/fhir/sid/ndc',
code: '50580045850',
},
{
system: 'http://www.nlm.nih.gov/research/umls/rxnorm',
code: '209387',
},
],
};

Example: Tylenol

Naming Data: Identifiers

One issue in healthcare applications is that the same entity can have many different identifiers in different systems. For example, a patient might be identified simultaneously by their:

  • Social Security Number (SSN)
  • Medical Record Number (MRN)
  • Medicare Beneficiary Identifier
  • Driver's License Number

FHIR anticipates this complexity by allowing each resource to have multiple identifiers.

Each identifier is defined by a (system, value) pair. As with CodeableConcepts, the system acts as namespace for the identifier, and must be specified as an absolute URL to ensure that it is globally unique.

Refer to this blog post for best practices on using identifier system strings.

Using the identifier system allows you to simplify your healthcare applications by consolidating data in a single resource, while allowing different systems to access the data by different ID schemes.

Example: Patient with two medical record numbers (MRNs)

The example Patient below has three identifiers: an SSN and two MRN identifiers from different hospital systems.

{
// Resource Type (i.e. "class name")
"resourceType": "Patient",
// Unique id for this resource
"id": "j_chalmers",
// Patient Name (could have multiple)
"name": [
{
"use": "official",
"family": "Chalmers",
"given": ["Peter", "James"]
}
],
"identifier": [
// Social Security Number ID (US-SSN)
{
"system": "http://hl7.org/fhir/sid/us-ssn",
"value": "011-11-1234"
},
// MRN - Hospital 1
{
"system": "http://hospital-1.org",
"value": "MRN-12345678"
},
// MRN - Hospital 2
{
"system": "http://hospital-2.org",
"value": "0987AZ6"
}
]
}

Listening for changes: Subscriptions

FHIR has a built-in Subscription resource that is used to define a push-based subscription to resources in the system, analogous to web-hooks. A Subscription has two primary elements:

  • criteria: This is a string expression that defines which resources to listen to, specified in FHIRPath format. This subscription is invoked whenever a resource that matches the criteria is created or updated.
  • channel: this describes the kind of action that the Subscription will take when it sees a matching resource. Currently, the possible values are rest-hook, websocket, email, and message.

In Medplum, a powerful feature is to to use a Medplum Bot as the endpoint of the rest-hook channel. This allows you to run an arbitrary piece of code in response to data changes and automate your medical workflows. See our Bot-Subscription tutorial for more information.