Loading Synthea FHIR Data with Logic Apps and Functions in Azure Government

Fast Healthcare Interoperability Resources (FHIR) is a draft standard describing data formats and elements (known as “resources”) and an application programming interface (API) for exchanging electronic health records. I have written about how to set up several types of FHIR servers (Firely and HAPI FHIR) using Azure PaaS components. I have also demonstrated how you can use Azure API Management (APIM) with a FHIR server. In this blog post, I will be demonstrating how one can use a combination of Azure Functions and Logics Apps to load FHIR bundles into FHIR server. I will be doing all of this in Azure Government to illustrate that there is a complete suite of integration services (iPaaS) available in Azure Government. All of these services are, of course, available in Azure Commercial as well.

The scenario looks something like this:

I have deploy a FHIR Server in an Azure Web App. In this case, I have used the HAPI FHIR Server in Azure. You can find several examples in my GitHub repository with FHIR server templates. I have also added API Management (APIM) to allow policy, user, and key management. You can read more about that in my post on FHIR server with Azure API Management. I used APIM add an additional endpoint /, which was not added by default. Several FHIR servers will accept FHIR bundles of type transaction at the root endpoint and store all resources in the bundle as a single transaction.

In order to generate synthetic data, I have used the Synthea patient generator. It is an excellent tool. It generates a FHIR bundle of type collection for each patient. We want to make some changes to these bundles, specifically we want to change the bundle type to transaction and make a few other adjustments. I have created an Azure Function App that hosts a simple function to perform this task. For details on how to create an Azure Function, you can take a look at this tutorial. The code for the Function looks like this:

[js]
module.exports = function (context, req) {
json = req.body;

if (json.type == "collection") { // synthea
json.type = "transaction"
json.entry.forEach(e => {
let method = e.fullUrl && e.resource.id.indexOf("urn:uuid:") !== 0 ? "PUT" : "POST"

e.request = {
method,
url: method == "PUT" ? `${e.resource.resourceType}/${e.resource.id}` : `${e.resource.resourceType}`
};
})
}

context.res = {
body: json
};
context.done();
};
[/js]

It was inspired by (shamelessly copied from) the tag-uploader from the SMART on FHIR project. Using this Azure Function, we can simply POST a Synthea resource bundle and get a modified bundle back ready to be committed to the FHIR server.

The orchestration is done with a Logic App, which is configured to trigger when a blob is added to a storage account. It will pick up the blob, use the Azure Function to convert it, and then POST it to the FHIR server (through the API management). Here is the flow in the Logic App:

Notice that we are providing the APIM key to post to the converted FHIR bundle to the FHIR server.

And that's it, we now have a workflow where we can add new patients to an Azure Storage Account, where they will get picked up by the Logic App, converted, and loaded into a FHIR server. This can, of course, be expanded. One could imagine test results being committed to storage accounts or notes being emailed, which would trigger a Logic App and so on. All the components have been deployed using managed services (no virtual machines) and all of these services are available within Azure Government.

Let me know if you have questions/comments/suggestions.