Conformance Rules for iGuide Authors
The FHIR Base specification provides a number of profiling mechanisms that iGuide authors can use to exert rules for data and system behaviors. The content below provides key details on the profiling mechanisms and points to examples of how the mechanisms are applied within a profile.
While the primary recommendation of this guide is to use the pan-Canadian profile directly within your implementation guide, the guidance below can help you understand the typical constraints utilized in pan-Canadian profiles, as well as the rules that need to be followed if your jurisdictional guide "re-profiles" (i.e., adds rules) to a pan-Canadian profile.
Cardinality
All attributes defined in FHIR have cardinality as part of their definition. A cardinality defines the minimum number of required appearances and its maximum number. These numbers specify the number of times the attribute may appear in any instance of the resource type. This specification only defines the following cardinalities: 0..1, 0..*, 1..1, and 1..*. Profiles that describe specific use cases may use other values for cardinality within the limits of the cardinality defined by the base resource.
An example of how cardinality is applied on a base resource is:
When Profiling or Re-Profiling
One key function of profiles is to change the cardinality of an element. A profile can restrict the cardinality of an element within the limits of the base structure it is constraining. This table summarizes what types of restrictions are allowed:
derived (across) base (down) | 0..0 (prohibited) | 0..1 (optional) | 0..n (optional, many) | 1..1 (required) | 1..n (at least 1) |
---|---|---|---|---|---|
0..1 | yes | yes | no | yes | no |
0..* | yes | yes | yes | yes | yes |
1..1 | no | no | no | yes | no |
1..* | no | no | no | yes | yes |
When a profile is constraining another profile where there are more cardinality options (e.g. low is not just 0 or 1, and high is not just 1 or *), the same principles still apply: the constraining profile can only further tighten what the base profile allows.
Note for Authors: Applying a cardinality constraint in your profile has a significant impact on the data being exchanged. The Guidance for FHIR IG Creation describe how best practices can be maintained when profiling - specifically with regards to avoiding customization and fragility that can result from over constraining cardinality. For example:
- When the lower bound cardinality is tightened to a 1, instances (records) that do not supply that information (or a data absent reason when allowed) are considered non-conformant and applications processing the content could reject the instance as an invalid resource.
- Constraining the upper bound cardinality also has significant impact to implementers, often requiring the development of a custom interface to uphold the constraint. The exchange of legacy data should be considered in both scenarios.
- Constraining the upper bound cardinality to 0, effectively indicates that an element is prohibited and should result in an error if the element is populated in an instance.
Postel's Law ("be conservative in what you do, be liberal in what you accept from others") is a critical philosophy for IGuide authors to incorporate into their work- particularly in relation to profiling. Changes to cardinality should be carefully considered and only applied after alternatives (i.e., must-support, invariants) have been explored and it is determined strictly mandatory for the facilitation of the use case.
Examples
For further examples showing how cardinality can be changed within a profile, see the JSON excerpt for the Patient Resource here.
MustSupport
Must-support flags are used to indicate data elements that systems conforming to a given implementation guide must support, in an appropriate, IG-specific sense. Such fields are not necessarily Required elements, i.e. an instance can be valid even if non-required must-support fields are missing. Must-support flags has no influence on the validity of a resource, but instead serve to communicate expectations to implementers.
The base FHIR specification does not apply MustSupport flags to any Resources. The meaning of mustSupport is also not defined in the base specification. The meaning of MustSupport is defined in each implementation guide. Profiles can provide this definition in one of two ways:
- They can provide detailed Obligations within a profile that provide coded expectations for what defined actors must support.
- While the Obligation Extension is still new (and evolving), it provides a consistent and potentially machine processable way for profiles to define their expectations for system behaviors.
- They can describe their expectations in ElementDefinition.definition, the general StructureDefinition.description or in other documentation for the implementation guide that includes the profile.
- This provides authors with the most flexibility in describing the expectations of the profiles, however expectations that are only conveyed in narrative context may be more difficult for implementers to discern
A typical example of an element with a MustSupport flag is:
A typical example of a profile that applies obligations at the element level (and structureDefinition level) is:
Examples
For further examples showing how MustSupport can be applied within a profile, see the JSON excerpt for the Patient Resource here.
For further examples showing how Obligation Extensions can be applied within a profile, see the JSON excerpt for the Patient Resource here
When Profiling or Re-Profiling
There are rules for how MustSupport is inherited when a profile with MustSupport flags (and definition) are re-profiled.
Notably, a MustSupport flag applied on a parent profile is inherited into the child profile and cannot be removed (i.e., by indicating mustSupport=false on an element previously marked mustSupport=true).
The definition and/or obligations of mustSupport flags applied on the parent profile are also inherited into the child profile and cannot be removed. Definitions and/or Obligations can be added in the child profile, particularly for different actors, but existing parent expectations cannot be undone or loosened. For example:
- A Profile of Condition might indicate that a "client" (obligation actor) has the obligation to "handle" (obligation code) the Condition.recordedDate.
- When re-profiled, the original expectation applied on the Condition Profile is upheld but the author may choose to also add additional codes for that actor and/or additional actor + obligation code pairs to further specify: "patient-facing application" (obligation actor) has the obligation to "display" (obligation code) the Condition.recordedDate.
Terminology & Binding Strength
Terminology provides an overview and guide to the FHIR resources, operations, coded datatypes and externally-defined standard and FHIR-defined terminologies that are used for representing and communicating coded, structured data in the FHIR core specification and profiles.
Almost all the elements that have a coded datatype are bound to a valueSet. In FHIR valueSets are represented as a ValueSet Resource. Both the valueSet itself and its applied binding strength in a FHIR Resource or FHIR Profile have an impact on implementer behavior.
The binding strengths are associated with various degrees of flexibility as to how rigidly the valueSet should be followed:
Binding Strength | Binding Strength Definition |
---|---|
required | To be conformant, the concept in this element SHALL be from the specified valueSet. |
extensible | To be conformant, the concept in this element SHALL be from the specified valueSet if any of the codes within the valueSet can apply to the concept being communicated. If the valueSet does not cover the concept (based on human review), alternate codings (or, data type allowing, text) may be included instead. |
preferred | Instances are encouraged to draw from the specified codes for interoperability purposes but are not required to do so to be considered conformant. |
example | Instances are not expected or even encouraged to draw from the specified valueSet. The valueSet merely provides examples of the types of concepts intended to be included. |
When Profiling or Re-Profiling
Commonly the FHIR Base specification will define an example or preferred valueSet and binding strength for a given element, though there are some cases that have a valueSet binding of extensible or required.
These original strengths have to be considered when a profile author desires to change the terminology binding strength and/or value set for an element. These changes have to occur within the limits of the base structure it is constraining.
The table below summarizes the various changes that are allowed to be made depending on the Base Binding Strength:
Allowed to Change Derived Strength To: required | Allowed to Change Derived Strength To: extensible | Allowed to Change Derived Strength To: preferred | Allowed to Change Derived Strength To: example | |
---|---|---|---|---|
Base Strength: required | yes | no | no | no |
Base Strength: extensible | yes | yes | no | no |
Base Strength: preferred | yes | yes | yes | no |
Base Strength: example | yes | yes | yes | yes |
A typical example of an element with a bound ValueSet is:
For further examples showing how new bindings can be applied in a profile, see the JSON excerpt for the Patient Resource here.
Extensions
Extensions are defined as additional common requirements across healthcare which are not part of the base FHIR profiles. It is expected that all additional valid requirements will be implemented as extensions.
Every element in a resource can have extension child elements to represent additional information that is not part of the basic definition of the resource.
An extension is made up of the following structure:
- Canonical URL of an extension definition that defines the content and meaning of the extension,
- Value element attached to the extension,
- Defined data type for the extension and its value,
- Cardinality for the root element, the value, and other nested elements.
Examples
A typical example of an element with an extension is:
For further examples, see the JSON excerpt for the Patient Resource here.
When Profiling or Re-Profiling
Extensions are a great tool to add-on additional content into your profile. If you define extensions that have a coded/CodeableConcept value, and you expect them to be re-profiled for maximum reuse, consider defining the extension.value without a fixed binding to allow for customization of value sets based on the needs of your implementers.
Note for authors: Prior to introducing the extensions in your guide, consider whether those extensions are critical to the use cases that you have defined for your guide. If you have determined an extension is needed, always start by attempting to use a globally defined extension in the FHIR Extension Registry, followed by nationally defined core extensions, then IG-specific extensions before defining your own.
On additional best practices on extensions in general, please view IG Best Practices - Guidance for FHIR IG Creation v0.1.0.
Slicing
Slicing is a complex profiling mechanism that allows authors to define patterned constraints on elements that may occur more than once (e.g., in a list/array). A simple example of slicing we see in Canada is the application of slices on the identifier element that conditionally require the supply of system and value if a Patient.identifier.type = "JHN".
Examples
Example: Jurisdictional Health Number (JHN) sliced in patient profile identifier.
When Profiling or Re-Profiling
While slicing seems like a powerful visual aide to IGuide authors - it is ultimately a tool to apply strict conformance rules on instances that are intended to be evaluated by servers.
Slicing can also be used for things like enforcing use of certain Observation.category codes to define the category of observation (e.g., "social-history", "laboratory") to provide downstream systems a predictable anchor to inform database mapping. Slicing can be used to enforce the ordering of codings that are supplied to ensure the first coding is always from a defined valueSet.
Rigid patterning expectations on instances, ultimately translates to customization of interfaces to ensure conformance. For this reason, authors should exercise caution when using slicing to ensure that impacts to systems providing new and legacy data are assessed and desired.
Slicing can also introduce challenges for re-profiling. Like other profiling constraints, slices are inherited. If you are expecting to re-profile, consider whether the slices you have defined will be equally applicable to the downstream profiles (as they can only be removed through notation and/or prohibition).
Note for Authors: Previously Pan-Canadian guides were used for socializing terminology that is applied by jurisdictions, which created a challenge in re-profiling because slices are inherited. Following the feedback with the community and evolution in the mechanisms available in FHIR, the approach for pan-Canadian guides has shifted to using the Additional Binding Extension to convey additional terminology that may be anticipated and that we maintain the use of slice on well defined elements.
Open and Closed Slicing
As described earlier, slices are rules applied based on patterning. These patterns can either be "Closed" or "Open".
Closed slices do not permit additional content to be inserted into the payload beyond what is present in the order of the slices created in this profile. Whereas open slices allow for additional set of values to be added in at any point of order of the slices within this element.
Note: An additional variation of open slicing exists that is called "Open at End" which allows the system to add additional information but at the end of list of slices created.
Examples
An example of open slices can be seen above with the JHN sliced in the patient profile.
For further examples, see the JSON excerpt for the Patient Resource here.
Invariants
Invariants, also known as constraints, are a way of expressing computable rules. They may apply to one or more values in instances, and are often used to express rules that are conditional (e.g., if Condition.abatement is populated then Condition.clinicalStatus must be "inactive", "resolved", or "remission"). These rules are commonly expressed in a syntax called FHIRpath.These invariants can also be applied to the profile as a whole or single elements which allows for customization on what can and cannot have the rules-based logic applied to it.
When Profiling or Re-Profiling
A key benefit of including invariants in a profile is that they allow the profile author to input computable logic into the profile that is more sophisticated than cardinality. When instances are validated against invariants, a message is produced at varying severities (i.e., guideline, warning, or error) if the instance does not meet the expressed rule. Often invariants are used to test whether vendors/systems have configured their systems to produce instances that meet conditional rules that arise from prioritized business and technical requirements (e.g., instance capabilities that MUST be demonstrated due to RFP, conformance, onboarding, etc.).
However, profile authors should use caution when enforcing invariants. Often legacy data may not meet requirements that seem reasonable for new data created by conformance systems. Rigidity in the data your system accepts/rejects based on your specific jurisdictional rules can lead to challenges in cross-jurisdiction interoperability.
All invariants are inherited when profiling or re-profiling. Only enforce invariants that you are confident will stand the test of time. Consider the use of usage notes to warn implementers about what’s ‘currently expected’ and/or handled as business rules within the system. If too many invariants are put into a profile or an implementation guide, it can make it cumbersome for both onboarding and host systems to conduct testing on the full set of rules to ensure that every aspect of the guidelines is accounted for.
If invariants are determined to be necessary for conformance or onboarding, consider applying a lesser severity level (e.g., warning, guideline) to ensure they are flagged but do not result in rejection of instances that do not meet the invariant.
Example:
Description: "Patient.name.given or Patient.name.family or both SHALL be present"
- severity = #error
- expression = "family.exists() or given.exists()"
- xpath = "f:given or f:family"