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
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
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"
}
}
Querying Data: Search
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:
- ICD-10 - Diagnoses.
- LOINC - Clinical measurements and lab results.
- RXNorm or NDC - Medication.
- SNOMED - Workforce administration, clinical findings.
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',
},
],
};
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)
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 arerest-hook
,websocket
,email
, andmessage
.
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.