Posting laboratory service requests to OpenELIS Global

Hey @ccwhite23, @ibacher and @janflowers,

I’m posting this a bit ahead of time since we barely started work on EIP-1, but as a matter of nailing the specs, I am wondering if we could take a look at the way you guys are creating orders in OpenELIS Global. This is what I presume is done, since OpenELIS Global is a HAPI FHIR server, as posting service requests to it.

We will have a Camel route that does just that in the end, at least that’s the plan at the current juncture.

Cc @mksrom @ruhanga @wyclif

So the iSantePlus -> OpenElis Global flow doesn’t directly post orders or patients to OpenElis Global. Instead, we use FHIR Tasks and a polling mechanism. Basically, an order is created in OpenMRS which sets up a Task owned by OpenElis. OpenElis polls for those tasks and then pulls in the corresponding patient and order via the normal OpenMRS FHIR2 endpoints. When results are ready, OpenElis creates a DiagnosticReport and a Task for OpenMRS. OpenMRS runs a scheduled task that looks for those Tasks and pulls the corresponding DiagnosticReport resource from the OpenElis FHIR server.

I realise this flow is somewhat different from what you’re envisioning, but we thought this was the simplest way to handle reliability in the face of inconsistent connectivity.

The HAPI FHIR documentation has a pretty good example of how to use that library to post a bundle which conditionally creates a patient (i.e., creates the patient if it doesn’t exist) and always creates an observation here. Presumably, what you’d setup in the Camel route works somewhat similarly.

The iSantePlus -> OpenElis connection is setup here (for the OpenMRS / iSantePlus side) and here (for the OpenElis side).

1 Like

@ibacher what do you mean by “owned”, does OpenMRS persist the tasks in OpenELIS? If so, why not create the order directly right? So I’m assuming something else is happening.

Absolutely! One thing that will not have to be done in the POSTing Camel route. Pretty cool stuff this “conditional create”. Thanks a bunch @ibacher, this is all very useful stuff.

By “owned” I really just mean that we populate the Task.owner field with a value to indicate that OpenElis should process it. Basically, in the flow we ended up with, only OpenMRS “writes” to the OpenMRS FHIR server and only OpenElis writes to the OpenElis FHIR server.

@ibacher my understanding is that you have used the tasks on both ends to act as a system of queues of things to do. Whether it’s creating new orders on OpenELIS side or saving test results on OpenMRS side.

The details of how those tasks are cleared so that they don’t get polled again is to be found in each of those two projects.

How did you handle for each system to authenticate with the other?

From OpenMRS to OpenElis, I believe they use a client certificate. For authentication from OpenElis to OpenMRS, the only option we support right now is Basic authentication (i.e., username and password).

It’s worth mentioning that you can put any authentication mechanism you like in front of the FHIR module as long as it winds up populating the OpenMRS context. Obviously, this is only possible on newer versions of OpenMRS.

This is what we’ve done to start support for SMART on FHIR (which is a kind of protocol built on top of OAuth2 and OIDC).

Are you constrained to Core before 2.3.x?

For the FHIR module, yes (we’re trying to support 2.0.5+). For the SMART on FHIR stuff, we’re taking advantage of the pluggable credentials from 2.3 on.

At this point my thinking is that we will try to do something like this (and there is still much to unpack at each step):

  • A Camel “test orders” route that feeds off the main “debezium” route that filters for test orders.
  • The “test orders” route will take care of creating a FHIR transactional bundle patient + service request.
  • The “test orders” route will be able to authenticate with OpenELIS global to POST the above transaction.

That would be the easier leg, the way OpenMRS → OpenELIS. Then there is the other way around… There it is still unclear what is the way to go.

What is the maturity of the HAPI FHIR Subscription Server? Can OpenELIS be that? How is a subscription being configured, for example to broadcast test results? Which channel type to use, rest-hook? … etc etc.

All that vs using OpenELIS’ FHIR data exchange, but then how is that one configured? How did you guys configure this (presumably to poll tasks from OpenMRS)?

I was digging into the code base of OpenELIS a little… should we be worried that there is not a single unit test? Is it because 99% of it is the HAPI FHIR server and the rest is a lightweight shell around/alongside it? I mean, I guess since there is about 50 .jsp and 50 .java files in there, that has got to be 0.001% of HAPI FHIR’s code base in volume…

1 Like

In general, the HAPI FHIR JPA server is one of the most feature-complete general-purpose FHIR servers around and is probably the most widely-used FHIR server, so I’d trust their implementation of subscriptions are solid. (In the background, their subscriptions model is actually based on Spring Messaging).

Yes. We even talked to the OpenELIS team about utilising subscriptions at one point. The problem is that the HAPI subscription implementation is pretty tied to the JPA Server, so it’s features we (OpenMRS) would have to implement in our server.

Subscriptions in FHIR are represented as just another resource, which is used to manage what the subscription triggers on, what channel it uses, etc. Setting up a subscription would just be a matter of posting a document like:

  "resourceType": "Subscription",
  "status": "requested",
  "reason": "Integration with OpenMRS",
  "criteria": "DiagnosticReport?<some search criteria>",
  "channel": {
    "type": "rest-hook",
    "endpoint": <url>,
    "payload": "application/fhir+json"

To the Subscription endpoint of the OpenELIS FHIR server.

Almost certainly either rest-hook or message, which can at least be used to send relevant data and handled fairly easily.

The downside to FHIR Subscriptions is that there’s no real reliability mechanism built-in. I.e., when the triggering event happens, the subscription will attempt to send the requested message. If the message fails for whatever reason, then the notification could be lost. This is part of why we ended up with the polling workflow that we did, because it seemed necessary to have some kind of polling in place if only as a back-up to other messaging.

I can’t really comment on the OpenELIS-specific parts, but I’m sure @ccwhite23 or @janflowers can put you in touch with the OpenELIS team to discuss those concerns.


I’m bookmarking that answer, thanks @ibacher. A lot of promising stuff there.

@caseynth2 @rossumg could you provide any context here for OpenELIS?

Hi Christina,

Casey’s on leave, do you have a question?


Hi @rossumg,

I had a question in regards to the production-readiness of OpenELIS Global:

No apparent test code base “could” be fine if nobody intends to touch it. Perhaps is there a UI test suite somewhere? How is this project protecting itself against regressions?