OpenMRS and OpenFn

Is anyone using OpenFn to exchange data between OpenMRS and other systems?

Hi Jan,

I don’t know if anyone is running an OpenMRS integration in production right now. When we started building a lot of these open-source language packages a few years ago, OpenMRS seemed like it would be higher priority so we’ve actually already got a connector set up for it and our team (Open Function Group) has done some demo integrations with it. I’ll ping my colleague Aleksa—we’d be happy to show you how it works, and she might be able to connect you to other others who are using it.

Taylor

Hello Taylor,
I am working as a senior Software developer for Friends in Global Health (FGH) Mozambique, we are currently exploring enterprise integration frameworks options for linking OpenMRS with other systems such as lab. Did you manage to show a demo of how that would work as promised in the email below? If you did, could you please provide a link to the recording if there is one?

Thank you,
Willa

Hi Willa - Thanks for the note. As Taylor mentioned, we have an OpenFn connector language-openmrs (https://github.com/OpenFn/language-openmrs) to speed up integration setup. OpenFn can connect any app, but using helper functions from our open source language-packages such as getPatient() helps to further speed up integration setup. Example below:

// Search for OpenMRS existing patients by EMR Id
getPatients(
{
identifier: dataValue(‘emrId’),
v: ‘full’,
},
{
exactlyOne: true,
}
);

Users can also leverage the generic request function req() to have an OpenFn job send any HTTP request to the OpenMRS API: https://github.com/OpenFn/language-openmrs/blob/master/README.md#make-a-request-to-any-openmrs-endpoint. These jobs can be triggered by an event (i.e., a new CommCare form submitted), or by a timer (i.e., every night @ 11p, sync data with OpenMRS).

I don’t think we have a demo video on hand, but check out this OpenMRS job I recently helped Partners in Health prototype: https://github.com/OpenFn/pih/blob/master/searchPatient.js. The job uploads CommCare forms to OpenMRS as encounters in real-time, but first searches for existing patients before uploading new data. This duplicate-checking step seems to be a very important process in most of our partners’ workflows.

I’m wondering what OpenMRS integration use cases are you exploring? Are you hoping to connect with other apps like CommCare or DHIS2? I’d be happy to share more relevant examples and even help you prototype a use case (which we can then record and share back to the Community for future reference!). If helpful, here are some demo videos we have available: https://www.youtube.com/watch?v=Iy4ChEKcQzQ&list=PL1pD3-abjHJ2fNDk0g3A0jrowIVwTZyhR

Hi Aleksa,
Thank you for such a prompt response. Could you clarify how exactly I can access the patient resource once returned by the gePatient() function call? Is it a promise? I see in the PIH example you have provided there are two function calls, the first says “1. Search for OpenMRS existing patients using EMRID” which is fine, however immediately after it there is a function call to create an encounter. I fail to understand how all this works, does it wait for the search? if not how does it tell whether the patient already exists or not? could you please clarify? Thank you.

Coming back to our use case. We have a server that contains all patients lab results and which is also updated periodically, we call this server “staging server”. On the other hand we have OpenMRS instances running in each health facility. Currently, we have a module running on these OpenMRS instances that is making periodic requests to the staging server for lab results. We are looking for a comprehensive solution that can be used to link these two systems together with minimal or no coding at all. How can this be achieved using OpenFn considering that most of the OpenMRS instances do not have public IPs?

Thanks again,
Willa.

Hi Mhawila,

Re: your use case, let’s set up a quick call (https://calendly.com/taylor-downs) to make sure we’re understanding everything correctly. If those instances are not available from the internet (no public IPs?) you might be looking at a local deployment or connecting OpenFn-cloud through sort of VPN. That’s no problem, but will require a bit more setup and maintenance work on your end. Either way, moving from a custom module to an integration platform like OpenFn will give you much more visibility, error-handling capabilities, and administrative controls over how these systems talk to one another.

Your question about accessing the returned patient is a great one! It gets to the core of how jobs work in OpenFn. Each “operation” is a function that returns a promise and is actually passed__“state” alongside its arguments__. State is a json object which consists—at least—of a configuration key (containing some sort of login/authentication information) and a data key (containing the body of the message/event/received request that triggered the execution of a particular job. (If it’s a real-time, event-based job. Jobs can also run periodically with a cron schedule, or based on the success or failure of another job.)

In Aleksa’s job, she’s passed the exactlyOne option to get patients, so she wants the run to fail if we find 0 or >1 matching patient, based on that emrID field (see how it comes from state.data! She knows that next operation (createEncounter) will only be executed if the first operation succeeds. Think of a job expression as a whole bunch of promise.then calls which take state and return state. That same pattern is extended over cronjobs (so that the second run of a cronjob inherits the final state of the first run—which is very useful for keeping a “cursor” while polling an external API for new data) and flow jobs (so that when job A succeeds, job B has access to its final state).

I have two thoughts here:

(1) If you want a low/no-code solution, let’s define the business requirements that your team has for the various integrations and then write one or two “helper functions” so that all your users need to see on OpenFn is something like this:

identifyAndUpdate(
dataValue(‘uuid’),
dataValue(‘patient’)
);

(2) If you’re keen to dig into the mechanics of OpenFn/core (which is great!) then I’d check out https://github.com/OpenFn/openfn-devtools and play around with the alterState operation, either on the hosted iPaaS (see https://docs.openfn.org) or locally, using our open-source stuff. To follow Aleksa’s pattern but really crack open the hood, you could write something like this:

getPatients({ something with the initial state });

alterState(state => {
console.log(‘Do what you’d like in here…’);
console.log(state);
console.log(‘But always return state!’);
return state;
});
createEncounter({ something with the updated state });

Hope this helps! Excited that you’re digging in, and looking forward to speaking with you about the OpenMRS project.

Taylor

Hi Taylor,
Thank you for such a detailed explanation. I get the gist of now. I appreciate you taking the time to understand our use case, I can’t thank you enough. I have already sent a calendar invite for the same. The scheduling application stated that a Google meet would have been created if I specified any location but it hasn’t been. So I have created the Google meet manually, here is the link https://meet.google.com/dsd-dena-khb

Looking forward to an interesting discussion.

Brilliant. Speak to you then.

Taylor