Building Portable FHIR Apps
Challenges and a Case Study
Jan 10, 2019
FHIR® is supposed to allow all health systems to talk to each other. But, is it really a common language? In this post, Healthcare Tech Lead Andrew Marcus dives deeper, and looks into some of the challenges in building portable FHIR® apps.
Meanings and Context
According to George Bernard Shaw, “The United States and Great Britain are two countries separated by a common language.” While Britons and Americans both speak English, there are subtle differences in how words are used. For example, does your taxi driver place your luggage in the boot or in the trunk? Does your fish and chips come with fries when you were expecting crisps?
Many languages which sound nothing alike can share a common ancestor. Take German and Dutch, for instance. To order a cheese sandwich in Germany, one would go to the Bäckerei and order Brot with Käse. In the Netherlands, you’d order Brood with Kaas from the Bakkerij. As you can see, sometimes you’d use the same word (spelled in a different way), but other times you’d use a different word altogether. And, like many languages, one word may have several meanings depending on the context.
So, what does this have to do with FHIR® and software?
Language clusters and dialects
Essentially, each FHIR® data source speaks its own dialect, or you could even say, its own language.
At its core, FHIR® is just a set of building blocks; you could think of them as letters. FHIR® profiles form individual languages that clusters of FHIR® services can all speak. Like human languages, many distinct FHIR® profiles can derive from a common parent. Organizations should define profiles for their specific use cases and schemas.
A FHIR® profile typically defines:
- A common set of use cases
- A common set of FHIR® schemas, including extensions to the core schemas
- A common set of terminology codes
Typically, each profile is packaged with an Implementation Guide. This is a human-readable document which describes how the profile should be used and which explains any nuances. The FHIR® community has published common profiles, such as US-Core, from which most other profiles are derived. While this does not make all profiles compatible, it creates “families” of related profiles. Families can often operate with each other in some ways, but not in others.
For example, profiles A and B may use the same definition for Patients, but use different code systems and fields in their Observations. Software designed to work with profile A could potentially merge together patient records from profile B. But, it might not be able to understand the observation records from profile B.
Adding to the complexity, each FHIR® profile ties to a particular version of the core FHIR spec (DSTU2, STU3 or the newly released R4). These major versions have significant changes between them and aren’t really compatible. For the first time, R4 will define some normative resources which will be forward-compatible with future versions. At the time of publishing, no implementations currently in production use R4, and the normative resources only represent a small subset of the spec.
Cardiac Consultant – A Case Study
Now, let’s take a look at Cardiac Consultant, a FHIR®-enabled app we built in partnership with Mile Two. Cardiac Consultant is a user-friendly tool which helps doctors educate patients about their individual risk for heart disease and stroke. We built the app to connect directly to a patient’s records in Cerner’s Electronic Health Record (EHR) system. When a doctor launches the app, it uses this data to calculate different risk factors for cardiac disease.
On the left, you’ll see filters showing factors of the patient’s health, such as age or blood pressure. If the app is unable to calculate the value of a particular factor (due to missing data in the patient’s EHR), we designed it to default to a value which has no impact on the models. The app alerts the doctor to set the missing values manually in order to get an accurate risk prediction for the patient.
Once the doctor sets the filters to match the patient’s current health status, he/she can adjust the filters to show the patient how lifestyle changes could affect their cardiovascular risk over time.
Loading the data
Using the SMART-on-FHIR® standard, the app can easily load much of the patient’s health data. For example, Name, Age, and Gender can be loaded directly from the Patient resource.
But since healthcare providers may use different codes when entering measurements, values such as Height, Weight, Blood Pressure, and Cholesterol are slightly trickier. However, these can be determined based on Observation resources. The app runs through these in reverse-chronological order until it finds an observation with a measurement we care about. Each observation includes a terminology code to indicate what the measurement was for.
Fields such as Conditions, Medications, and Encounters also require a little more thought. For example, to answer the question “Is this patient receiving treatment for diabetes?”, we have to know several things:
- Does the patient have diabetes? Diabetes is a complex medical condition with many different manifestations. There are over 500 different codes used to represent it across three of the main terminologies: SNOMED, ICD-9 and ICD-10.
- Is the patient taking medication used to treat diabetes? Doctors use a variety of medications to treat diabetes. Each medication has many different formulations, each of which has various terminology codes. And, doctors may use these medications to treat other conditions too. For example, Metformin is a common diabetes drug, but it is also used to treat other insulin-related diseases, such as PCOS.
Although FHIR® can support linking a medication to the condition it is being used to treat, Cerner does not expose this relationship, so answering these two questions is the best we can do.
So far, Cerner has only implemented a portion of the FHIR® spec. Their implementation of FHIR® does not yet support the Family Member History resource. This piece is useful to answer questions like, “Does this patient have a family history of heart disease?” While this data is available in Cerner, Cerner lists it as Conditions, with special codes to indicate the condition belongs to a family member rather than the patient. Now that we know about this, our app can interpret the data correctly, but it took us some time to figure out.
Cerner’s implementation of FHIR® also affects search parameters. For example, it’s possible to query Observation resources to get back only those that match a particular set of codes. But, Condition resources do not support this. As a result, our app needs to get back the entire list of Condition records for a patient and loop through them until we find one with a code we care about. While this is not inherently a problem, we did have to base our architecture decisions around the supported search parameters.
The world in profile
Since Cardiac Consultant was a finalist in Cerner’s Code App Challenge, several other EHR vendors expressed interest in including it in their app stores. However, we quickly realized that the FHIR ecosystem is not yet ready for plug-and-play. Currently, the ecosystem consists entirely of point-to-point integrations between individual FHIR apps and individual FHIR servers. So, building an app to work with one EHR does not guarantee that it will work with any other EHR without significant modifications.
Ultimately, when you say your app supports FHIR®, what you really mean is that it supports a particular version of FHIR® using a particular profile or set of related profiles. But there may be data sources you want to connect your app to that implement a different version of FHIR® or a different set of profiles. How might you build an app that can handle this?
To find out, stay tuned for the next part of this series. In Part 2, we’ll peel back these layers and show you what you need to build an app that is truly interoperable.