In our previous articles on FHIR validations, we highlighted how slicing, FHIRPath, and binding could be used to verify resources on an FHIR server. However, with so many FHIR validation examples available, how do you know when to use one over the other, or what is the difference between Slicing vs. FHIRPath vs. Binding?
To answer that question, our business analyst, Sveta Medved, put together a table with FHIR validation examples demonstrating the difference between FHIR slicing vs. FHIRPath vs. binding that you can use as a quick reference. The options are rated based on how easy it is to perform or maintain and the outcome of the FHIR validation operation.
Comparison: Slicing vs. FHIRPath vs. Binding
Slicing
Purpose:
Slicing is a mechanism used to specify constraints on repeating elements in FHIR resources. It allows you to differentiate between the multiple instances of an element based on some set of criteria like value or cardinality.
Use Cases:
- Constrain repeating elements to have unique values for a particular sub-element.
- Specify cardinality constraints on subsets of repeating elements.
Strengths:
- Flexibility: Allows multiple instances of the same element but with different constraints.
- High expressivity: You can define slices based on a wide variety of conditions.
Limitations:
- Complexity: Handling slicing can add complexity to FHIR implementation.
- May require custom logic for interpretation.
FHIRPath
Purpose:
FHIRPath is a domain-specific language for traversing and querying FHIR data models. It is employed for expressing constraints, queries, and calculations on FHIR data.
Use Cases:
- Navigate FHIR resources.
- Make conditional statements in FHIR resource definitions.
- Validate resource attributes.
Strengths:
- Precision: Can articulate very specific conditions and constraints.
- Readability: Easier to read and understand than XPath or other similar languages.
Limitations:
- Learning curve: Requires understanding of FHIRPath syntax and semantics.
- May not handle all complex logic without additional programming.
Binding
Purpose:
Binding is used to attach a specific set of allowed values to an element. It enforces that the values of elements conform to predefined value sets or code systems.
Use Cases:
- Ensuring that an element’s value is one of a specific set of allowable options.
- Setting mandatory or optional code systems for elements.
Strengths:
- Simplicity: Easier to implement compared to slicing or FHIRPath.
- Standardization: Promotes use of standardized terminologies.
Limitations:
- Rigidity: Doesn’t provide the expressive flexibility that slicing or FHIRPath can offer.
- Limited to predefined value sets or code systems.
Each of these approaches has its own merits and limitations, and the optimal choice depends on the specific requirements of your FHIR implementation. For a comprehensive understanding of integrating genomic data within the FHIR framework, refer to our FHIR genomics complete guide, which provides in-depth insights into this specialized area.
Below we will delve into how the different methods of validations compare based on universal two common scenarios.
Scenario 1. Validate code can use only one value from the list
FHIR Validation Example: We want to validate that a Patient resource has a name with the use set only to official.
Slicing
In this case, we slice Patient.name by value with closed rules:
"slicing": {
"discriminator": [
{
"type": "value",
"path": "use"
}
],
"ordered": false,
"rules": "closed"
}
And then add slicing to the Patient.name.use:
{
"id": "Patient.name:official.use",
"path": "Patient.name.use",
"short": "usual | official | temp | nickname | anonymous | old | maiden",
"definition": "Identifies the purpose for this name.",
"comment": "Applications can assume that a name is current unless it explicitly says that it is temporary or old.",
"requirements": "Allows the appropriate name for a particular context of use to be selected from among a set of names.",
"min": 1,
"max": "1",
"base": {
"path": "Patient.name.use",
"min": 0,
"max": "1"
},
"type": [
{
"code": "code"
}
],
"fixedCode": "official",
"constraint": [
{
"key": "ele-1",
"severity": "error",
"human": "All FHIR elements must have a @value or children",
"expression": "hasValue() or (children().count() > id.count())",
"xpath": "@value|f:*|h:div",
"source": "http://hl7.org/fhir/StructureDefinition/Element"
}
]
}
If we post the use for the name as any other than `official`, we’ll receive an error message.
FHIRPath
If we use FHIRPath for this validation, we’d need to add a constraint to Patient.name.use:
{
"key": "official",
"severity": "error",
"human": "Only official could be used for `use`",
"expression": "$this = official",
"source": "http://hl7.org/fhir/StructureDefinition/Element"
}
Then we’d also receive an error if we post a patient resource with Patient.name.use other than official.
Binding
We could also use binding to validate the same thing. In this case, we’ll need to create a ValueSet with only one value and change valueSet for `binding` in the profile:
{
"id": "Patient.name.use",
"path": "Patient.name.use",
"short": "usual | official | temp | nickname | anonymous | old | maiden",
"definition": "Identifies the purpose for this name.",
"comment": "Applications can assume that a name is current unless it explicitly says that it is temporary or old.",
"requirements": "Allows the appropriate name for a particular context of use to be selected from among a set of names.",
"min": 1,
"max": "1",
"base": {
"path": "Patient.name.use",
"min": 0,
"max": "1"
},
"type": [
{
"code": "code"
}
],
"constraint": [
{
"key": "ele-1",
"severity": "error",
"human": "All FHIR elements must have a @value or children",
"expression": "hasValue() or (children().count() > id.count())",
"xpath": "@value|f:*|h:div",
"source": "http://hl7.org/fhir/StructureDefinition/Element"
}
]
"binding": {
"strength": "required",
"valueSet": "http://example.com/fhir/ValueSet/only-official"
}
}
As a result, we have the same validation done in three different ways. Each method is viable. In the end, it comes down to personal preferences and goals. For this case, we recommend FHIRPath. It does the same job but is more convenient to maintain for profile authoring. It has fewer JSON lines, meaning it’s easier to read, make changes, and find errors.
Scenario 2. Validate extension in a profile should be at least one with a concrete profile
FHIR Validation Example: We want to check that among all extensions in the resource, there is the one we expect.
Slicing
If we want to check that at least one extension is what we expect, we could use slicing. For example, such FHIR slicing is used in FHIR’s CH EMED Medication Card profiles.
FHIRPath
To perform the same validation with FHIRPath, we add a constraint to the extension:
{
"key": "ehealth-00036",
"severity": "error",
"human": "Language extension is mandatory",
"expression": "extension.exists(url = 'http://ehealth.com/fhir/StructureDefinition/ehealth-humanname-language')",
"source": "http://hl7.org/fhir/StructureDefinition/Element"
}
In this case, both options are decent and simple to maintain. But if you are creating an Implementation Guide, slicing will give you a more human-readable format because you will be able to see in the tree structure which pieces of slicing are used. This also helps with future FHIR integrations.
Conclusion
We hope this quick reference guide and FHIR validation examples will help you validate your profiles more conveniently and apply the right FHIR validation type for your business case. Refer to our article on how to perform FHIR validations for more detailed information.
If you are just getting acquainted with the FHIR standard for your project and lack the proper FHIR expertise, our engineers and analysts are ready to fulfill your needs. Contact us via the website form.
FAQ
- How can FHIRPath be used to validate specific data elements within FHIR resources?
- Data Type Validation: FHIRPath can be used to confirm that a specific element within a resource conforms to the required data type. For example, you could validate that an age field is a numerical value and not a string.
- Constraint Checks: It allows for defining invariants or conditional constraints that elements in a resource must meet. For instance, you could specify that a Patient resource must have either an email or phone number.
- Logical Operations: FHIRPath can validate logical relationships between different elements. For instance, you might want to validate that the end date of an appointment is later than the start date.
- Are there tools or libraries available for implementing FHIR validation using slicing, FHIRPath, and binding?
You can use a FHIR Server like Kodjin that supports all types of validation methods, including slicing, binding and FHIRPath.