FHIR Models for Resources not in OpenMRS

FHIR has a large number of resources available and, of course, not all of them are useful in an EHR context or in the contexts OpenMRS is normally used in, but a great many of them are, including many resources for which we have no OpenMRS analogue or poorly-defined ones.

In the past, we’ve occasionally created new tables to represent FHIR resources we need, e.g., the Task resource was pretty central to the lab workflow—and is probably pretty central to being able to “FHIR-ize” any order workflow1—so we added a Task class. This works well enough, but it has some serious limitations to it. In particular, to keep the Task flexible enough to be able to reference the appropriate resources (including for basedOn which can be a reference to any FHIR resource), we end up with a model that lacks any of the normal referential integrity we might have, and consequently our ability to write performant queries against Task. For instance, our current implementation can handle a query to get any task created as part of a given encounter (/ws/fhir2/R4/Task?encounter=893c6850-ff9e-4b11-bc59-52d60c1cc0d7), but we couldn’t add the flexibility we have with other resources to implement chaining to allow things like queries for tasks related to encounters by characteristics of that encounter (e.g., find me all tasks related to active encounters for John Smith: /ws/fhir2/R4/Task?encounter.status=in-progress&for:Patient.name=John%20Smith), at least not in a performant way. The overall point is that this probably isn’t the best way to add FHIR resources for things not already covered by the OMRS data model.

However, there are certainly needs to represent FHIR resources that currently don’t fit comfortably in the OMRS data model or at least to use FHIR as a model for expanding the OMRS datamodel, but we need to think carefully about how we do this. Plausible ways of moving forward are:

  1. We store things in the Obs table either as Obs or ComplexObs (e.g. DocumentReferences, MedicationDispenses etc.). We also have done this with Immunization, though the results are probably a little brittle. This probably means ensuring that we have standarised models in CIEL for these things and that implementers are happy using those CIEL models.
  2. We create bespoke models that address narrow use-cases, e.g. create some sort of model for MedicationDispense more similar to existing OMRS data model objects. This allow us to best take advantage of the tooling in the FHIR2 module to provide a decent user experience at the expense of probably needing to limit what data we can actually accept.
  3. We continue to create new data models after the model of Task, where we can represent all the data a Task can store, but lose referential integrity and chainability.
  4. We fall-back to something like a real FHIR server, e.g., by embedding a HAPI JPA server to serve those resources we can’t represent in the OMRS model. This allows us to keep the full flexibility of FHIR resources and search, but means we need to come up with a strategy for synchronising this FHIR instance with the resources already available in OMRS.’

Something like 4 has been the sort of thing I’ve been planning on, but it has some obvious draw-backs, in particular, how do resources in the secondary FHIR server reference resources in the OMRS database?

I’d appreciate any thoughts or commentary from the community on this.


1: FHIR’s workflow model distinguishes between “Requests”, e.g., an order and “Events”, e.g., a medication dispense or diagnostic report. “Tasks” are the resource used to track what happens between the request and the corresponding event (if any), including things like was the order rejected?


My approach would be to first ask, why are these resources not in OpenMRS? Is it because we do not yet have real, on the ground, practical use cases (non theoretical) for them? Or are they resources that we are storing as Obs (Like we used to do for Conditions and Diagnosis)?

If we have current real use cases for these missing resources, then i find Option 2 more appealing because of the advantages you stated and for being lightweight compared to option 4.

To emphasise this point, when i say real use cases for adding new models, i mean those models that implementations would need and use, even when they do not care about FHIR.

1 Like

Could you expand a bit more on why we’d lose referential integrity and chainability? Or why it’s not performant?

Btw, digressing a little but why does FhirTask extend BaseOpenmrsMetadata?

Basically a mismatch between the database model and what FHIR allows. FHIR Tasks have several fields that are references to any other FHIR resource, so e.g., the Tasks table could have several Tasks where the for field pointed to: a patient, a practitioner, an encounter (and also a visit), an observation, etc. To handle that right now, we just store the raw reference (usually something like Patient/123 or Encounter/123, etc. The full form is necessary so we can also store things like http://myfhir.example.com/fhir/Patient/123 Or urn:uuid:<uuid>). Handling all of those basically means that we’re just storing text.

I suppose we could handle the most common case that via a very wide reference table with columns like reference_patient_id, reference_order_id, reference_encounter_id, reference_visit_id, reference_provider_id, reference_user_id, reference_location_id, reference_obs_id, etc. But even then we need to deal with some polymorphism. For instance both Immunization, Observation, and some versions of Condition all reference the obs table but there FHIR search capabilities depend on what kind of resource it’s supposed to represent.

The solution to all of these issues is to follow something like what HAPI does where we store things as essentially a document and build secondary indexes to support the querying, but at that point, it’s much less effort to just use HAPI.

Making Task extend Metadata might’ve been a mistake, but is probably (for now) an easily reversible decision. I think Task is in a weird place where it’s not metadata in the sense of, e.g., the concept dictionary because they (might be) created or retired relatively frequently and probably aren’t suited to be managed by Iniz, but they also aren’t exactly Data because they don’t necessarily pertain to patients or even have anything to do with patients or even workflows including patients (Tasks are, in essence, how you communicate any workflow state in FHIR, including for purely system-level tasks).