FHIR profiles allow an organization to dictate the structure and content of data coming into the server.
- Optional elements are made mandatory
- Codes are bound to specific ValueSets
- Approved extensions are enforced
This improves the quality and consistency of data flowing into and out of a FHIR server. Everyone knows what they’re getting.
But what if you want to lock down a resource to more strictly enforce the data flowing in? In short, you want to be able to say:
I want THIS precise data and nothing more.
Why would you want to do this?
Let’s say we’re “Big Healthcare Company”. Apps and data sources from across the organization are sending data into our central FHIR server. It’s a managed server sitting on the Cloud and as with most managed FHIR servers we don’t control the underlying database.
From a data governance perspective we want to know exactly what data is coming into our FHIR server.
We’ve had meetings with privacy, with legal, with compliance — in ten or twenty countries around the world. Regulations regarding patient data are different in each one of these countries.
We decide that the only way to manage all this is to enforce very strict rules on what data is allowed into the organization’s FHIR server. Just enough to meet the requirements and NOTHING more.
In particular, we’re worried about unexpected extensions that could contain anything finding their way into the FHIR server — all without us knowing.
That’s the use case. How do you do it?
I started by creating a Patient profile in Forge. In the profile I changed the cardinality of every element I didn’t want to “0..0” — essentially removing them from the resource. This left me with a small number of elements that were allowed for Patient.
- Name
- birthDate
- Identifier
I then set the cardinality of all extensions for those three elements and their attributes to “0..0” — no extensions permitted. This wasn’t possible in Forge as it doesn’t expose extensions for individual elements. I had to manually edit the StructureDefinition JSON file to achieve this.
Here’s what the Profile looks like in Forge.

I loaded the profile into my test server and tried it out by sending in Patient resources with restricted elements populated. As expected, they were all rejected. I then tried creating Patient resources with extensions on various elements such as Patient.birthDate or Patient.name.given. These too were successfully blocked.
It seemed like I succeeded in creating a fully restricted profile, but there was one use case that proved difficult.
What if I wanted to allow specific extensions into the resource while still blocking unexpected extensions? To test this I chose to create a new extension and add it to the root of the patient resource.
To get this working I needed some help, as the documentation around complicated profile creation barely exists. Ward at Firely was kind enough to weigh in and offer some assistance.
I added the new extension to my Patient profile and adjusted the slicing on Patient.extension so that it was closed and had a cardinality of 0..1. I then loaded both StructureDefinititions into my test server and ran some POST requests.
Everything worked as expected. I could create or update a Patient resource with the new extension, and I was unable to add a different extension.
The Profile was successfully locked down.
Back to our “Big Healthcare Company” with their host of apps sending in data from around the world. If their aim is to restrict the data flowing in so that it gives them exactly what they want and nothing more, this can be achieved using a closed profile like the one I constructed.
The difficulty lies in how to manage allowed extensions while blocking all other extensions, a complex task that requires manual editing of the StructureDefinition JSON file and some advanced knowledge of profile slicing.
Here’s the StructureDefinition for the profile: Github-1
The StructureDefinition for the extension: Github-2
A test patient resource: Github-3
Opinions are strong on whether closed profiles like this should be used at all, with many in the FHIR community opposed to them on principal. My feeling is that this a case where business needs and requirements sometimes differ from the loftier interoperability goals that lie behind FHIR itself.
FHIR is an “open” standard but sometimes business needs require “closed” data.
---