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.
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 a set of Resource Types, similar to classes, that have been built for healthcare applications.
Resources can represent a broad range of healthcare ideas, from very concrete healthcare items (e.g. Patient, Medication, Device) or more abstract concepts (e.g. Procedure, Care Plan, Encounter).
A Resource
is composed of multiple fields, called Elements
, each of which can be a primitive type (e.g. strings, numbers, dates) or a complex type (e.g. JSON objects).
Example
The example below shows an example Patient resource, represented as JSON. 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",
// Paitient 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"
}
]
}
References: Linking Resources
Often times, multiple resources contain related data. For example a prescription is related to the receiving patient, and a diagnostic report may consist of multiple observations.
To create pointers between objects, we use Reference
elements. A FHIR Reference
is not a Resource
, but a data type for a resource Element
. The full FHIR Reference
object has the follow structure:
{
"reference" : string, // 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
fields.
Example
The example below shows a MedicationRequest resource two references: subject
(i.e. the patient) and requester
(i.e. 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"
}
}
Identifiers: Naming Resources
One issue in healthcare applications is that the same resource can have many different identifiers, depending on the context. For example, a patient might be identified simulataneously 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 identfiers.
Each identifier is defined by a (system, value)
pair. The system
acts as namespace for the identifier, and must be specified as an absolute URL to ensure that it is globally unique.
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
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"
}
]
}
Search Parameters: Querying Resources
There are many cases in which a client would like to query resources by a certain field value. FHIR resources cannot be searched by arbitrary fields. Instead, the specification defines specific search parameters for each resource that can be used for queries.
You can find the search parameters on the reference page for each resource. Refer to the FHIR Search documentation for how construct search queries using these parameters.
Example
For example the Medication resource defines the following search parameters:
- Identifier
- Code
- Expiration Date
- Form
- Ingredient
- Ingredient Code
- Lot Number
- Manufacturer
- Status
Subscriptions: Listening for changes
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.
Codeable Concepts: Standarding Data
The healthcare system commonly uses standardized coding systems to describe healthcare concepts such as diagnoses, procedures, medical equipment, and billing information. These coding systems are crucial for sharing data between systems because they provide standardized values that organizations know how to process. Some common coding systems include LOINC, SNOMED, CPT, ICD, and HCPCS.
The same concept being defined in mulitple coding systems. To handle this mapping from concept to system, the FHIR standard defines a data structure called a CodeableConcept
. A CodeableConcept
contrains an array of (system, code)
pairs, along with a text field to describe the overall concept.
Below is an example CodeableConcept
, that defines a negative test result outcome in the SNOMED and ACME Lab systems.
{
// Text description of the concept
"text": "Negative for Chlamydia Trachomatis rRNA",
"coding": [
// Encoding of the value in SNOMED system
{
"system": "http://snomed.info/sct",
"code": "260385009",
"display": "Negative"
},
// Encoding of the value in ACME LAB system
{
"system": "https://acme.lab/resultcodes",
"code": "NEG",
"display": "Negative"
}
]
}