This year we completed a project in the medical space where we leveraged FHIR as the data storage mechanism. FHIR is the Fast Healthcare Interoperability Resources specification and defines a data model, interchange format (xml or json) and REST API specification for disparate systems to exchange healthcare data. Previously, every medical system would expose its own APIs and data interchange mechanisms, and so to write some middleware syncing things together, you needed to speak a lot of protocols and translate between them. With FHIR, each system should ostensibly speak the same protocol and simplify a lot of work for the implementer.
Here’s some miscellaneous observations from working with it.
Medical data is complicated, who would have thought!
It’s pretty tough for someone new to the medical domain to know where to store pieces of data.
How is an Observation, Specimen, ServiceRequest related? The spec describes the relationships in pretty mechanical terms (is-a, has-a relationships) but the domain knowledge behind that understanding takes time to develop. It can be confusing to figure out where you’re going to stick the information.
The complexity of the data model, however, forces you to think about how things are actually complicated in the real world! For example, a Patient does not have a name, as I might naively model it. They have a list of names, given names, common names, nick names, family names. You’re forced to acknowledge this and handle your data accordingly.
Speaking of names, almost everything in FHIR is a list. There seemed to be very
0..1 relationships between entities, almost everything was
meant the client library modeled it as a list. There was a lot of hunting
through lists looking for the element with the expected
One of the most common list elements we had to search through were “Extensions”.
FHIR recognizes the need to store additional data about its resources that they
couldn’t plan ahead for. Imagine app-specific metadata that is not a standard
medical domain concept: the most obvious place to store that is in each
extension data which is basically a
key-value store of arbitrary
But remember, everything is a list, so you don’t get a nice
Dictionary<string, string> interface into
extensions, you get a
List, and you’ll write a lot
of code looping through items.
The value of an
extension can be any core datatype, a Reference to another
resource, or even another nested Extension or (of course) a list of extensions.
Turtles all the way down!
FHIR has some good ideas on REST API design.
DELETE all have well defined semantics. For example, if you have a
client-provided identifier (like a GUID you know ahead of time) use
if you want the server to generate an identifier, use
Everything is URL identified, so when there are links between resources its not
"patientId": "abcdef", but
I’d never seen this before in other REST APIs, but FHIR defines a
TransactionBundle for making multiple transactional operations. Imagine you
need to create and upsert a set of different
resources, and you want all that to happen under the same database transaction:
either all succeeding or failing together. In most REST apps I’ve worked on
you’re just out of luck. But FHIR has a Resource for a bundle of related
relationships, like cramming multiple API calls into a single giant JSON blob
and the server can run it as a database transaction. Nifty!
Similarly, Search returns a
Bundle, which can have lots of different resources
them. However, it’s up to app code to join them back together.
FHIR defines a lot of primitive types, which I thought was neat. Instead of just
having a number type, they have
Range, and other primitives that are constrained to important
domain concepts. Sometimes they were hard to work with, but they forced us to
store valid data and to consider the real complexity of modeling healthcare
The specification is very document-oriented, it considers a
Patient and its
ServiceRequests as different resources with different APIs. Semantically (in
our domain at least), a
ServiceRequest is nested under a
ServiceRequests) but the shape of the actual JSON does not reflect
that, they are separate resources and are linked together with the
It would be hard to implement this spec against a relational database.
The provider we were using did use relational database under the hood though it just stored compressed JSON in a single Resources table. This design did cause us some issues in search performance, but gave us access to the TransactionBundle mentioned above.
Here’s Apple Health showing my COVID booster raw FHIR data it got from my local
health provider’s system. This is an
Immunization resource, you can see how it
has reference to my Patient record, and some
Coding about what vaccine it was.