An in depth analysis of Microsoft Azure’s FHIR API versus Google Cloud’s Healthcare API for FHIR as of August 2020
Disclaimer: I am employed at Google Cloud as a Solution Architect.
After spending a week at the FHIR DevDays conference back in June, two main players stuck out as leaders in the fully managed FHIR (Fast Healthcare Interoperability Resources) API Cloud space — Google Cloud and Microsoft Azure. At the event the two organizations had relatively similar demonstrations, showing HL7v2 to FHIR conversions, de-identification functionalities, and visualization capabilities for each. I began to wonder, is there documentation on the difference between the two organizations and offerings? So I decided to dig.
This is an in-depth analysis of the current state for each API. I attempt an unbiased review of both Azure API for FHIR and Google Cloud’s Healthcare FHIR API. This reflects the state of both APIs as of August 2020. Azure launched to public preview on February 7th, 2019 and was generally available October 21st, 2019. Documentation for the product can be found here. Google Cloud launched to Early Access on March 16th, 2018, Beta on April 4th, 2019 and was generally available April 9th, 2020. Documentation for the product can be found here.
Although you won’t find it in the public documentation, the underlying infrastructure for the API is built on Spanner, the same technology that powers Google Cloud Spanner. Google Cloud Spanner is described as a “fully managed relational database with unlimited scale, strong consistency and up to 99.999% availability.” It is a first of its kind database, claiming to break the CAP theorem, having both analytics and transactional functionalities. Spanner ensures “TrueTime” external consistency which is the strongest form of consistency one can achieve for transactions in a distributed system. On top of the Spanner infrastructure, Google Cloud’s Healthcare API is tightly integrated with additional proprietary technologies such as indexing and queuing features to achieve its performance and scalability.
Azure offers two types of deployments for their FHIR API. The first is an open source version that can be deployed on any infrastructure, including Azure, and enables application developers to manage their own server and control the backend. The second is a managed deployment; this article focuses exclusively on the managed API.
For Azure’s managed deployment, the API leverages a managed Cosmos DB instance. Cosmos DB is described as “a fully managed NoSQL database service for modern app development with guaranteed single-digit millisecond response times and 99.999% availability.”
There have been a lot of comparison articles between Cosmos DB and Spanner, so I will not cover the database differences, rather, the API differences in this article. Both APIs leverage performant, high availability back-end systems for their FHIR data storage, yet neither API provides direct access to the underlying datastore. While Azure has published SLA numbers here, Google has yet to publish their SLAs for the product.
Overall, Google Cloud has less published information on their infrastructure as a fully managed service, which is deliberate since Google has abstracted away the need to understand how the API is built so that users can focus solely on the functionality. A true comparison of the infrastructure would come from the performance numbers and tests against each, which is not covered in this article.
Both API presentations at FHIR DevDays had users leverage something other than their managed service in order to visualize the data. Google Cloud demonstrated the export capability from the FHIR store to their managed Data Warehouse product BigQuery — with no need for schema definition or DDL scripts. They also demonstrated how their recent acquisition of Looker can allow for users to access and visualize the data sans-code. From Azure’s DevDays demo, they leveraged PowerBI by connecting it directly to their FHIR store. While this required more schema definition than the Google counterpart (albeit, UI based) the end result was similar in nature.
Google Cloud’s FHIR API is fully managed and does not require users to configure, set, or otherwise tune their infrastructure in any way. While this may be unfamiliar to legacy or on premise users, this can be a huge advantage for reducing overhead and operational costs usually associated with similar developments or an open source implementation. Not only does the database automatically scale to meet additional capacity needs with no operator intervention, the servers required for operations also automatically scale with use.
CosmoDB requires users to not only manage their partitioning but also set the number of request units for CosmoDB. Request Units (RUs) are what operators utilize for throughput and/or operations against the database. When the database is provisioned, users set the amount of RU’s they want to reserve for capability — meaning, users have to pay for enough resource units in Cosmos to ensure FHIR resources are available and accessible to users at all times. This may mean users are over-provisioning and underutilizing their infrastructure, or paying for more than what they may need. More about how to configure Cosmos DB can be found here.
Azure end users have to describe their scaling parameters and configurations in order to meet scaling needs thus it does not seamlessly scale without customer management like its Google Cloud counterpart. Additionally, it may be difficult for users to plan their capacity and usage of resource units, since there is a lack of documentation on how many and what type of API requests require what amount of RUs.
Note: This section only touches on the storage pricing of each of the APIs. For API call pricing, the two vendors handle the requests differently (Azure by pre-purchased resource units, Google by on-demand pricing). Due to the lack of a 1:1 comparison, API based pricing is not evaluated. This pricing analysis was conducted on 08/11/2020.
Google Cloud’s pricing is relatively straightforward. When the API launched to GA, they removed the runtime and server costs. Structured storage has multiple tiers, their free tier up to a GB per month, $0.39 per GB per month up to 1 TB, then it drops to $0.34 per GB per month above 1 TB.
Azure’s pricing can be broken out into two different categories, server costs and storage costs. Unlike its Google Cloud counterpart, Azure does charge for server cost, which is an additional $292.00 a month if the FHIR server is running 24/7. For storage pricing, Azure’s as-is storage price may look more appealing at first, coming in at $0.25 per GB per month, however, there are additional costs beyond the API storage that users need to consider. According to Cosmo DB’s documentation here, each GB of data also requires 10 RU/s for storage on top of the storage pricing. Since 100 RU/s is 0.008/hour, and assuming users want to store for 24 hours a day for a month (30 days) — that means there is an additional $0.576/GB charge for resource units just to store the data. This turns the $0.25/GB/month that is advertised into $0.826/GB/month (calculation for these assumptions can be found here).
After calculating the necessary infrastructure costs just to store data, Azure comes in more than double for storage costs of what GCP is (comparing $0.39/GB/month for GCP to $0.826/GB/month for Azure). Google Cloud does not have any runtime costs where Azure has almost 300 dollars a month for each store. When you factor in the fact GCP’s pricing model is pay for what you use, which can be more appealing to buyers, versus Azure’s model is pay for what you think you might need: couple this with Azure’s ambiguity on how many resource units are needed for API calls, various transactions, etc, and the cheaper pricing model GCP has, Google Cloud has a more appealing FHIR pricing model.
I have gone to both pricing calculators and calculated the amount required to store 100 GB of data for a month. Google came in at $155.61 dollars per month (here), while Azure sat at $315.36 dollars per month (here, under “saved estimates”).
FHIR Version Support Comparison
The following table lists the currently supported versions by each API. DSTU2 support may be important to you if your ecosystem includes systems that produce or consume FHIR in this format.
FHIR Operations and Server-Wide Operations Comparison
There are also several extended operations the FHIR community has defined that Google Cloud supports that are currently not supported in the Azure product. Patient $everything gives users the ability to fetch all the resources around one patient and is currently only supported in the Google Cloud product. Observation $lastn is a second FHIR wide call that allows users to pull the last “n” number of observations for a certain subject, and is currently also only supported in the Google Cloud product. Google also has a list of extended operations supported such as concept map translate.
Finally, there is a lack of bulk import functionality in Azure’s FHIR API, as it is missing from their open source documentation and was called out on several community posts. The lack of bulk import for the Azure FHIR store can be difficult for users who are looking to ingest bundles that are already persisted somewhere else. The lack of documentation for their store-wide operations makes it difficult to understand which operations user may not be able to perform. Conversely, Google Cloud supports a wide variety of server wide operations that can be performed on the FHIR store, with supporting documentation here.
Rest API Calls Comparison
Transaction Bundle Support Comparison
One of the largest advantages Google Cloud has is the support for transaction bundles. Azure’s managed FHIR API does not support transaction bundle types which can make streaming implementations difficult. Transaction bundles allow for multiple operations in a single request — often these transactions are connected. For example, if your bundle has an Encounter and an Observation resource — transaction bundles ensure if one resource fails the bundle fails — versus batch may write one without the other. What this means is that your server might store an Observation without ever recording the Encounter. Furthermore, batch calls do not allow for users to reference other resources inside the bundle, as they do not create the same server-assigned identifiers. This could become detrimental when users are attempting to build something like a Provenance resource in FHIR that needs to be able to reference other resources. This can make it extremely difficult to join resources in analysis that were processed in a batch bundle — as the traditional primary key is missing. For more information on business identifiers, visit: https://www.hl7.org/fhir/resource.html#identifiers
Search can be an extremely useful FHIR operation for users. The following table has general search functionalities and what each product supports. On top of this table, Google supports a number of advanced search capabilities such as sorting, chained parameters, and reverse chaining which are not supported in the Azure environment.
Google Cloud’s Healthcare API has built-in functionality for de-identification of FHIR resources. Since it is built into the API product, the de-identification functionality is also covered under the Google Cloud BAA and is a true managed service. This also means the API can be called from the Google Cloud Console in the Healthcare Data Browser for added simplicity.
In terms of functionalities, Google Cloud allows users of the de-identification FHIR endpoint to create their own rules for processing FHIR resources and create custom de-identification templates. GCP’s de-identification also supports customization at the field-level and offers additional customization at the infotype (e.g. AGE, LOCATION, etc.) level and sub-field level. On top of the functionalities within the API, there is a second product in Google Cloud, called the Cloud Data Loss Prevention API, that allows for further redaction of strings, images, and tabular data.
Azure recently released an open source project called FHIR Tools for Anonymization. According to documentation, this tool suite helps users de-identify 17 types of PII both on-premise and in the cloud. The tool is designed to process R4 data and allows for configurations at the field-level.
It is important to understand the workflow of the tool in order to compare it with Google Cloud’s counterpart. The tool pulls data from Azure’s blob storage and processes the data on Data Factory with OSS pipelines. The only pipelines that have been published are bulk pipelines, thus sending bulk FHIR data through Data Factory and back to object storage. The issue lies in the fact there is no bulk-import functionality in the FHIR API as discussed earlier in this post. That means, there is no workflow on how to do data de-identification and to bring it back into the FHIR server in bulk.
Configurations only support the built in methods — keep, redact, date shift, and crypto hash. Azure’s de-identification functionality is also limited, they only support rules-based processing of FHIR R4 data. Azure’s response for free-text sections is to delete them, meaning that the user loses access to a significant amount of medical and patient context within the record. Azure calls out that they do not allow for custom de-identification methods in the documentation here.
Azure came later to the table, releasing their functionality in March of 2020 when compared to Google Cloud’s release in 2018. The difference also lies in the fact GCP’s is a managed service that means users are not responsible for the underlying tool set instead of setting up a specific environment for the process like Azure’s. Azure does not have a defined workflow that allows users to store their de-identified data back into the FHIR store once complete, leaving it in object storage. This is a stark contrast to Google’s endpoint which reads from a FHIR store and writes into a secondary FHIR store, with no need for additional products or pipeline.
From a de-identification perspective, Azure’s tools support only structured data and are limited to rules-based processing. They are also limited in only being able to apply rules at a field-level, so there is no logic for sub-field and infotype specifications like Google supports. Finally, Google goes beyond rules-based processing by introducing some of the AI-based processing to detect PII/PHI within sections of free-text. This allows for retaining non-PII/PHI components of free-text fields, which can be useful for downstream analyses and applications.
Google supports DSTU2, STU3, R4 — so the variety of use cases Google Cloud can support is more robust than Azure’s that only supports R4.
Notifications and Database Changes
Google Healthcare API has the ability to associate every FHIR store with a Pub/Sub topic for push based notifications that can be configured on the UI per store. This is a managed service that automatically scales by distributing loads without pre-purchasing involved. By creating multiple subscriptions to each topic, routing for each notification can be done within the product without processing. To trigger a processing event beyond routing, users have to manually create triggers for Pub/Sub topics.
Database changes rely on CosmosDB change feeds, which do not currently log deletes or specific types of operations. The change feed can send data to an Azure Function or a Change Feed Processor for further analysis. Users have to manually create triggers for the change feed if utilizing an Azure Function using Visual Studio or CLI tooling, or implement a change feed processor.
The ease of use that Google provides through Pub/Sub when monitoring database changes reduces the amount of custom logic in a streaming pipeline. Pub/Sub seems to be a more packaged solution when it comes to streaming analytics, as it has automatic capturing, storage, and routing built in, unlike its counterpart. The lack of logging for deletion or specific types of operations in the Azure environment, without custom code, could also lead to compliance issues or difficulty in further processing. Finally, Azure lacking support for a push model natively is a drawback when compared with the Google Cloud environment.
In a feature by feature review, Google appears to have more API functionalities, surrounding data functionalities (such as search and de-identification), and tighter integration with its larger product suite. Based on the storage pricing described in the ‘Pricing’ section above, Google also appears to have a more attractive pricing model, coming in around half the cost per GB (at 100 GB) compared with the Azure API. Try both out and decide for yourself at Google Cloud and Azure.
Google Cloud recently open sourced an engine that converts data into a common data model and provided reference mappings for HL7v2 to FHIR R4, HL7v2 to FHIR STU3, and FHIR to OMOP. This push to enable users to bring legacy data and streaming HL7 messages to their FHIR store is an additional differentiator for Google Cloud.